引言
在之前学习过的继承和多态中,我们对于类的继承关系有了深刻的理解。在Java中我们将类的继承关系抽象为一个自上而下的层级结构,上面是父类下面是子类,显然层级越高的父类所代表的范围越广泛,因此也更加的抽象。比如Object 是Java中的公共最高父类,那么Object 到底是个啥?好像它啥都是,又好像啥也不是。所以说Object 这个类通用性就非常广,同时也非常抽象(注意:Object 并不是抽象类,这里只是做了一个比喻)
假设我们有一个类,就比如说是图形类把,它可以用来表示所有的图形。图形有什么属性和功能呢?首先图形肯定是有面积的,所以图形也应该具备计算面积的方法。可是这个计算面积的方法应该怎么实现呢?图形的子类可以有很多,比如说正方形、三角形、圆形… 每一个具体的图形它们的面积计算公式是不同的,所以对于图形这个父类中计算面积的方法就很难去定义它的方法体。
public class Shape {
public double calculateArea() {
return
}
}
class Square extends Shape {
double sideLength;
@Override
public double calculateArea() {
return Math.pow(sideLength, 2);
}
}
class Triangle extends Shape {
double base;
double height;
@Override
public double calculateArea() {
return base * height / 2;
}
}
class Circle extends Shape {
double radius;
@Override
public double calculateArea() {
return Math.PI * Math.pow(radius, 2);
}
}
既然这么难去定义,能不能不定义方法体,直接让子类覆盖重写父类中的这个方法呢?。当然可以,程序员是不会和自己过不去的,既然存在一些类它们当中的一些方法是很难去定义的,索性咱就改改代码不去定义得了,废这个脑细胞都够耽误我摸一盆🐟了。
抽象方法
这个不定义方法体的方法,就是抽象方法。而定义抽象方法使用 abstract 关键字,被abstract 修饰的方法就是抽象方法。
定义格式如下:
修饰符 abstract 返回值类型 方法名(参数列表);
现在我们尝试使用abstract 关键字来修饰父类中的计算面积方法。
public class Shape {
public abstract double calculateArea();
}
当把这个方法定义为抽象方法后,编译器直接报错,提示我们在非抽象类中定义了抽象方法。 这是为什么呢?这里我们需要牢记一个规则:如果一个类包含抽象方法,那么该类必须是抽象类!
抽象类
抽象类是由abstract 关键字所修饰的类,抽象类主要用于被子类继承被覆盖重写其中的抽象方法,子类重写抽象父类的抽象方法的过程也被称作实现方法,对于子类实现的方法不能再加上abstract 关键字。
定义格式如下:
修饰符 abstract class 类名称 {
}
现在我们将图形类改为抽象类,再看看程序能否正常允许。
public abstract class Shape {
public abstract double calculateArea();
}
可以看到,子类实现了抽象父类的方法后,程序可以正常运行。不过关于抽象类还有许多需要注意的事项,下面一起来看一看。
抽象类的注意事项
-
抽象类不能被实例化。
抽象类的主要作用就是为了被子类继承并实现的其中的抽象方法,抽象类中大部分定义的都是没有方法体的抽象方法,所以对抽象类进行实例化没有意义。
-
抽象类作为一个类,其内部是有构造器的,不过抽象类的构造器并不是为了本类实例化,而是为了子类在实例化中加载父类结构而存在的。 -
抽象类中可以定义普通方法和属性。
-
抽象类中,不一定包含抽象方法,但是包含抽象方法的一定是抽象类。
未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计(比如一些工具类,其中定义了静态方法提供使用,无序对该类实例化)。
-
抽象类的子类,要么实现抽象父类的所有抽象方法,要么该子类本身也是一个抽象类。 -
一个抽象类A可以被另一个抽象类B继承,但是如果有另外的普通类C继承了抽象类B,那么普通类C所继承的所有抽象方法被必须被重写。
- final和abstract不能共存
final修饰类时表示该类不能被继承,final修饰方法时表示该方法不能被重写。
而abstract修饰的类需要被子类继承,abstract修饰的方法必须要被子类重写。
两个关键字功能相互矛盾,所以不可以共存!
注意点:final类中的所有成员方法都会被隐式地指定为final方法。
8. private不能用来修饰抽象方法。
在继承关系中我们学习过对于父类的private的方法,子类是不可见的,也就谈不上覆盖重写。
而另一个的原因是private所修饰的方法会被隐式的指定为final方法,这也说明了private所修饰的方法为什么不能被覆盖重写。
当方法被final或者private修饰时,该方法就从动态绑定转变为静态绑定,那么该方法也就失去了重写的意义。
-
抽象类是适用于多态性的。
抽象类满足多态的三个必要条件:
- 继承,抽象类的意义就是为了被继承。
- 重写,抽象类的抽象方法必须被重写。
- 向上转型,抽象类虽然不能被实例化,但是允许抽象类的引用指向子类对象。
可以看到,抽象类完美的契合了多态的三个必要条件。
|