参考资料
《Java语言程序设计(基础篇)》—— Y.Daniel Liang
前言
本人菜鸟,入IT只为当鼓励师。本编文章旨在对 Java 中的 抽象类 做总结
一、抽象类
1. 定义一个抽象类
// 抽象类
public abstract class Shape {
// 可以有属性
// private String color;
// 可以有普通方法
/* public void setColor(String color) {
this.color = color;
}
public String getColor() {
return this.color;
}
*/
// 抽象方法
public abstract double getArea(); // 获取面积
public abstract double getPan(); // 获取周长
public abstract void printShape(); // 获取周长
}
上方代码中的Shape类是一个抽象类,它表示一种形状。它拥有两个抽象方法, 分别为 getArea()
和 getPan()
。
- 抽象类需要在类头使用
abstract
修饰符修饰 - 抽象类中未实现的方法也必须加
abstract
修饰符修饰,我们把这些方法称为抽象方法。(区分于接口,接口中的方法默认修饰为public abstract
,不管有无加修饰词) - 抽象类中不仅可以含有抽象方法,还可以拥有自己的数据成员,包括属性和普通方法。(区分于接口,接口中的方法必须是抽象方法,属性必须被
public final static
修饰)
2. 继承抽象类并实现其抽象方法
public abstract class ShapeTest extends Shape{
public abstract double getArea(); // 获取面积
public abstract double getPan(); // 获取周长
public void printShape() { // 输出形状信息
System.out.println("我实现了Shape类的printShape方法,但没有实现其他两个方法,所以我还是一个抽象类");
}
}
// 正方形类
public class Square extends Shape {
private double len; // 边长
protected Square(double len) {
this.len = len;
}
public double getArea() {
return len * len; // 边长 × 边长
}
public double getPan() {
return 4 * len; // 4 × 边长
}
public void printShape() {
System.out.println("正方形");
}
}
// 圆形类
public class Circle extends Shape {
private double r; // 半径
protected Circle (double r) {
this.r = r;
}
public double getArea() {
return Math.PI * r * r; // π × 半径^2
}
public double getPan() {
return Math.PI*r*2; // 2 × π × 半径
}
public void printShape() {
System.out.println("圆形");
}
}
二、要点
- 抽象方法不能包含在非抽象类中。如果抽象父类的子类不能实现所有抽象方法,那么子类也必须定义为抽象。
- 包含抽象方法的类必须是抽象的。但可以定义一个不含抽象方法的抽象类,作用是使类不能创建实例,用来定义新子类的基类。
- 抽象类不可以创建对象,否则抛出
InstantiationException
异常(使用newInstance()方法创建抽象类或接口实例抛出的异常)。但是仍然可以定义它的构造方法,这个构造方法在它子类的构造方法中调用。 - 抽象类不可以用final修饰。因为抽象方法的实现由子类提供,需要子类继承该抽象类,而用了final修饰的类不能被继承。
- 即使子类的父类是具体的,这个子类也可以是抽象的。例如,Object类是具体的,但它的子类Shape是抽象的(所有类均继承Object类)。
- 子类可以覆盖父类的方法并将它定义为abstract。这很少见,作用是实现父类的方法在子类中变得无效。
- 抽象类的构造函数要定义为protected,因为它只被子类使用。
三、抽象类的好处
- 抽象类可以包含方法的实现细节,因此可以将子类中公用的逻辑上提,增加的代码的复用。
- 抽象类可以通过方法的覆盖来实现多态的属性,也就是运行期绑定,由JVM在运行时期根据对象的类型动态地决定调用哪一个方法。如下面的代码:
Shape square = new Square(2);
Shape circle = new Circle (3);
square.printShape(); // 正方形
circle .printShape(); // 圆形
square.getArea(); // 4
circle .getArea(); // 9π
square.getPan(); // 8
circle .getPan(); // 6π
四、抽象类的UML图形记号
在UML图形记号中,抽象类和抽象方法的名字用斜体表示。
五、示例:抽象的Number类
- Number类 来自于
java.lang.Number
,它是数值包装类、BigInteger、BigDecimal的抽象父类。
网友评论