在java中我们中abstract关键字来表达抽象。举个例子:
我们说车子都可以跑(run)。但有几个轮子,怎么跑,对于不同的车有不同的结果。自行车需要人踩着跑,汽车发动机推动跑等等,那么我们可以车表达为抽象类。
/**
* 车子类
*/
public abstract class Car {
public abstract void run();
}
/**
* 自行车
*/
class Bicycle extends Car{
@Override
public void run() {
System.out.println("人踩着跑。。。");
}
}
/***
* 汽车
*/
class Automobile extends Car{
@Override
public void run() {
System.out.println("发动机驱动跑。。。");
}
}
假如后面各种车,倒着跑、悬在空中跑随你怎么跑,只需要继承抽象类实现自己的业务就行了。相信大家对java抽象已有一个初步的印象了。
抽象方法:
1、从上面的例子中我们可以看到抽象方法跟普通方法是有区别的,它没有自己的主体(没有{}包起来的
业务逻辑),跟接口中的方法有点类似。所以我们没法直接调用抽象方法
2、抽象方法不能用private修饰,因为抽象方法必须被子类实现(覆写),而private权限对于子类来
说是不能访问的,所以就会产生矛盾
3、抽象方法也不能用static修饰,试想一下,如果用static修饰了,那么我们可以直接通过类名调
用,而抽象方法压根就没有主体,没有任何业务逻辑,这样就毫无意义了。
抽象类:
1、用abstract关键字来表达的类,其表达形式为:(public)abstract class 类名{}
2、抽象类不能被实例化,也就是说我们没法直接new 一个抽象类。抽象类本身就代表了一个类型,无法
确定为一个具体的对象,所以不能实例化就合乎情理了,只能有它的继承类实例化。
3、抽象类虽然不能被实例化,但有自己的构造方法(这个后面再讨论)
4、抽象类与接口(interface)有很大的不同之处,接口中不能有实例方法去实现业务逻辑,而抽象类
中可以有实例方法,并实现业务逻辑,比如我们可以在抽象类中创建和销毁一个线程池。
5、抽象类不能使用final关键字修饰,因为final修饰的类是无法被继承,而对于抽象类来说就是
需要通过继承去实现抽象方法,这又会产生矛盾。(后面将写一篇关于finally的文章详细讨论)
抽象类与抽象方法的关联:
如果一个类中至少有一个抽象方法,那么这个类一定是抽象类,但反之则不然。也就是说一个抽象类中可
以没有抽象方法。这样做的目的是为了此类不能被实例化。
如果一个类继承了一个抽象类,那么它必须全部覆写抽象类中的抽象方法,当然也可以不全部覆写,如果
不覆写全部抽象方法则这个子类也必须是抽象类
public abstract class Car {
public void mothod1(){
}
public abstract void mothod2();
public abstract void method3();
}
class Bicycle extends Car{
@Override
public void mothod2() {//需要覆写抽象方法mothod2
}
@Override
public void method3() {//需要覆写抽象方法mothod3
}
}
抽象类的构造器:
先来看一个例子:
public abstract class Car {
Car(){
System.out.println("抽象方法无参构造函数");
}
Car(String a){
System.out.println("抽象有参构造方法");
}
public void mothod1(){
System.out.println(this.getClass());
System.out.println("抽象类的实例方法");
}
public abstract void mothod2();
}
/**
* 自行车
*/
class Bicycle extends Car{
Bicycle(){
System.out.println("子类无参构造函数");
}
@Override
public void mothod2() {//需要覆写抽象方法mothod2
}
}
/**另一个包的测试类**/
public class Test {
public static void main(String[] args) {
Bicycle b = new Bicycle();
b.mothod1();
}
}
结果:
抽象方法无参构造函数
子类无参构造函数
class com.shaolin.service.impl.Bicycle
抽象类的实例方法
从上面的例子中可以看出:
1、抽象类是有构造方法的(当然如果我们不写,编译器会自动默认一个无参构造方法)。而且从结果来看,和普通的继承类一样,在new 一个子类对象时会优先调用父类(这里指的是抽象类Car)的构造器初始化,然后再调用子类的构造器。至此相信大家都会有这样一个疑问,为什么抽象方法不能实例化却有构造器呢? 对于这个问题网上也中说纷纭,没有确定答案。
既然它也属于继承的范畴,那么当子类创建对象时必然要优先初始化父类的属性变量和实例方法,不然子类怎么继承和调用呢?而它本身不能实例化,因为它本身就是不确定的一个对象,如果它能被实例化,那么我们通过它的对象来调用它本身的抽象方法是不是有问题。所以不能实例化有在情理之中。因此大家只要记住这个规定就行。
2、对于抽象类中的非statci(静态)和非abstract(抽象)方法中的this关键字(静态方法中不能有关键字this之前已经讨论过可以参考 关于静态static那些事)代表的是它的继承类,而非抽象类本身,这个好理解,因为抽象类本身不能被实例化。如果有多个继承类,谁调用this就代表谁。
抽象类有什么好处呢?
1、由于抽象类不能被实例化,最大的好处就是通过方法的覆盖来实现多态的属性。也就是运行期绑定
2、抽象类将事物的共性的东西提取出来,由子类继承去实现,代码易扩展、易维护。
网友评论