參考資料
《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的抽象父類。