Java 抽象類別 (Abstract Class)
抽象類別是不能被實例化的類別,用來作為其他類別的基礎。
基本語法
使用 abstract 關鍵字:
public abstract class Animal {
protected String name;
// 抽象方法:沒有實作
public abstract void makeSound();
// 一般方法:有實作
public void eat() {
System.out.println(name + " is eating");
}
}
抽象方法
抽象方法只有宣告,沒有實作,子類別必須實作:
public abstract class Shape {
public abstract double area(); // 抽象方法
public abstract double perimeter(); // 抽象方法
}
public class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
@Override
public double perimeter() {
return 2 * Math.PI * radius;
}
}
不能實例化
// Animal animal = new Animal(); // 錯誤!不能實例化抽象類別
Animal dog = new Dog("Buddy"); // OK,可以用子類別
完整範例
// 抽象類別
public abstract class Vehicle {
protected String brand;
protected int year;
public Vehicle(String brand, int year) {
this.brand = brand;
this.year = year;
}
// 抽象方法
public abstract void start();
public abstract void stop();
// 具體方法
public void displayInfo() {
System.out.println(year + " " + brand);
}
}
// 具體子類別
public class Car extends Vehicle {
private int doors;
public Car(String brand, int year, int doors) {
super(brand, year);
this.doors = doors;
}
@Override
public void start() {
System.out.println("轉動鑰匙,引擎啟動");
}
@Override
public void stop() {
System.out.println("踩煞車,熄火");
}
}
public class Motorcycle extends Vehicle {
public Motorcycle(String brand, int year) {
super(brand, year);
}
@Override
public void start() {
System.out.println("按下啟動按鈕");
}
@Override
public void stop() {
System.out.println("拉煞車,熄火");
}
}
抽象類別的特點
- 可以有建構子(但不能直接實例化)
- 可以有抽象方法和具體方法
- 可以有實例變數
- 子類別必須實作所有抽象方法,除非子類別也是抽象類別
public abstract class Animal {
protected String name;
// 建構子
public Animal(String name) {
this.name = name;
}
// 抽象方法
public abstract void makeSound();
// 具體方法
public void sleep() {
System.out.println(name + " is sleeping");
}
}
部分實作
子類別如果沒有實作所有抽象方法,也必須是抽象類別:
public abstract class Animal {
public abstract void eat();
public abstract void sleep();
}
// 只實作部分方法,也要是抽象類別
public abstract class Pet extends Animal {
@Override
public void sleep() {
System.out.println("Sleeping on the couch");
}
// eat() 還是抽象的
}
public class Dog extends Pet {
@Override
public void eat() {
System.out.println("Eating dog food");
}
}
抽象類別 vs 介面
| 特性 | 抽象類別 | 介面 |
|---|---|---|
| 方法實作 | 可以有 | Java 8+ 可以有 default |
| 建構子 | 可以有 | 不能有 |
| 實例變數 | 可以有 | 只能有常數 |
| 多重繼承 | 不支援 | 支援 |
| 存取修飾詞 | 都可以 | 預設 public |
更多比較請參考 Java 抽象類別 vs 介面。
何時使用抽象類別
- 有共同的程式碼:子類別共享相同的實作
- 「是一種」關係:Dog is an Animal
- 需要非 public 成員:需要 protected 變數或方法
- 需要建構子:初始化共同的狀態
// 適合用抽象類別:有共同的實作
public abstract class Employee {
protected String name;
protected double baseSalary;
public Employee(String name, double baseSalary) {
this.name = name;
this.baseSalary = baseSalary;
}
// 共同的方法
public String getName() {
return name;
}
// 抽象方法:不同員工計算方式不同
public abstract double calculateSalary();
}
public class Manager extends Employee {
private double bonus;
public Manager(String name, double baseSalary, double bonus) {
super(name, baseSalary);
this.bonus = bonus;
}
@Override
public double calculateSalary() {
return baseSalary + bonus;
}
}
模板方法模式
抽象類別常用於模板方法模式:
public abstract class DataProcessor {
// 模板方法:定義演算法骨架
public final void process() {
readData();
processData();
writeData();
}
// 子類別實作
protected abstract void readData();
protected abstract void processData();
protected abstract void writeData();
}
public class CSVProcessor extends DataProcessor {
@Override
protected void readData() {
System.out.println("讀取 CSV");
}
@Override
protected void processData() {
System.out.println("處理 CSV");
}
@Override
protected void writeData() {
System.out.println("寫入 CSV");
}
}