目录
有的类就不适合创建出实例,比如Animal类,它的子类Dog类,Cat类都可以创建出实例,但是Animal类在现实中就是抽象的类别,更细的划分才有具体的对象。所以Animal类不适合创建出实例。
这种没办法创建出实例的类,我们应该设置为抽象类。
大部分方法有具体的方法体,用来描述类的某种行为。但类里有的方法没办法写出具体的执行方式。比如Shape类的calPerimeter方法,只有Shape的子类triangle类或者rectangle类,才能写出具体的计算周长的算法。Shape类没有确定图形的形状,只是知道需要提供计算周长的方法,但具体的执行语句没办法写。所以,Shape类只能提供calPerimeter方法的签名,不能提供具体的方法体。
这种只能提供方法头,没办法提供方法体的方法,就是抽象方法。
抽象类可以用有得有失来形容,多了定义抽象方法的能力,失去了创建对象实例的能力。
抽象方法
抽象方法的定义
通用语法为: 访问修饰符 abstract 方法名(形参列表);
也就是只保留方法头,把方法体去掉,连{}都不要。抽象方法必须使用abstract关键字修饰。
注意:public void test(){} 这种是方法体为空的普通方法,不是抽象方法,虽然{}里面什么都没有,但是它保留了花括号本身。
抽象类
抽象类的定义
用abstract标记的类就是抽象类。抽象类无法创建实例(不管有没有抽象方法),只是为子类定义一个共同的规范,用来实现多态。
抽象类可以没有抽象方法,但有抽象方法的类只能是抽象类。抽象类的抽象方法可以是自身定义的,也可以是继承自父类或者来自接口。
抽象类的成员没有任何限制,5类成员(成员变量、方法、构造器、初始化块、内部类)都可以包含。抽象类虽然不能创建实例,但是需要拥有构造器。抽象类构造器的目的是为了被子类调用。
抽象类与具体子类
如果一个类继承了抽象父类,子类想要被定义为普通类,就必须实现继承到的所有抽象方法(来自直接抽象父类或者间接抽象父类)。如果子类没有实现抽象父类的所有抽象方法,那它本身只能被定义为抽象类。
抽象类的作用
抽象类虽然不能用于创建实例,但它设定了多个子类的通用模板,或者说定义一组子类共同的协议。子类总体上保留了抽象类的行为方式,同时可以在其基础上扩展和改造。
很多方法在抽象类的层次上是没办法写出具体实现的,那就定义为抽象方法,让具体的子类根据自身情况去实现方法体。
抽象父类也可以提供一个通用算法,通用算法需要使用某个抽象方法的结果。比如SpeedMeter类的周长计算方法只能是抽象方法,但它的计算速度的算法可以写出通用的算法,算法内部需要使用计算周长方法的返回值,等具体的子类实现了计算周长方法后,这个通用算法就可以得到具体结果。
用SpeedMeter抽象类举例:
public abstract class SpeedMeter {
private double turnRate;
public SpeedMeter() {
}
public SpeedMeter(double turnRate) {
this.turnRate = turnRate;
}
// 计算周长的算法目前只能是抽象方法,交给具体的子类继承
public abstract double calGirth();
public double getTurnRate() {
return turnRate;
}
public void setTurnRate(double turnRate) {
this.turnRate = turnRate;
}
// 可以写出计算速度的通用算法,该算法利用了计算周长的抽象方法
public double getSpeed() {
return turnRate * calGirth();
}
}
class CarSpeedMeter extends SpeedMeter{
private double radius;
public CarSpeedMeter(double radius, double turnRate) {
super(turnRate);
this.radius = radius;
}
// 子类实现了计算周长的具体方法,继承的计算速度的通用算法就能得到具体结果了
public double calGirth() {
return 2 * Math.PI * radius;
}
public static void main(String[] args) {
CarSpeedMeter car = new CarSpeedMeter(3, 15);
System.out.println(car.calGirth());
System.out.println(car.getSpeed());
}
}
abstract与其他关键字
abstract与final
abstract修饰的类或者方法,必须被子类继承和重写才有意义,而final修饰的类或者方法,就不能被继承和重写。所以,abstract与final修饰符不能同时使用。
abstract与static
类方法不能定义为抽象方法,因为父类的类方法只能被继承不能被重写,无法重写就没有必要定义为abstract。所以,static和abstract不能同时修饰某个方法。
但是,abstract和static可以同时修饰内部类,表示该内部类是属于外部类的抽象类,表示它需要被子类继承后才有价值。
abstract与private
private修饰的方法表示只在类内部有效,子类根本无法继承私有方法。所以private修饰的方法本身就隐式含有final。所以private与abstract也不能共同修饰方法。
abstract与其他成员
abstract不能用于修饰变量(成员变量和局部变量都不行)。abstract也不能用于修饰构造器,抽象类的构造器不能用abstract标记,因为构造器不能被继承,所以没有设置为abstract的必要。抽象类的构造器内部可以有代码逻辑,但只能被子类调用,不能用于创建抽象父类的实例。