Java 繼承 (Inheritance)
繼承讓子類別可以重複使用父類別的程式碼,建立類別之間的階層關係。
基本語法
使用 extends 關鍵字:
// 父類別
public class Animal {
protected String name;
public void eat() {
System.out.println(name + " is eating");
}
}
// 子類別
public class Dog extends Animal {
public void bark() {
System.out.println(name + " says: Woof!");
}
}
// 使用
Dog dog = new Dog();
dog.name = "Buddy";
dog.eat(); // 繼承自 Animal
dog.bark(); // Dog 自己的方法
繼承的特點
- 子類別繼承父類別的所有非私有成員
- Java 只支援單一繼承(一個類別只能有一個父類別)
- 所有類別都繼承自 Object
public class Animal { }
public class Dog extends Animal { }
public class Cat extends Animal { }
// 錯誤:不能多重繼承
// public class DogCat extends Dog, Cat { }
super 關鍵字
呼叫父類別建構子
public class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
}
public class Dog extends Animal {
private String breed;
public Dog(String name, String breed) {
super(name); // 呼叫父類別建構子
this.breed = breed;
}
}
呼叫父類別方法
public class Animal {
public void makeSound() {
System.out.println("Some sound");
}
}
public class Dog extends Animal {
@Override
public void makeSound() {
super.makeSound(); // 呼叫父類別方法
System.out.println("Woof!");
}
}
更多說明請參考 Java super 關鍵字。
方法覆寫 (Override)
子類別可以重新定義父類別的方法:
public class Animal {
public void makeSound() {
System.out.println("Some sound");
}
}
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Woof!");
}
}
public class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Meow!");
}
}
建議使用
@Override 註解,編譯器會檢查是否正確覆寫。更多說明請參考 Java 方法覆寫。
繼承與建構子
子類別建構子會先呼叫父類別建構子:
public class Animal {
public Animal() {
System.out.println("Animal 建構子");
}
}
public class Dog extends Animal {
public Dog() {
// super() 會自動呼叫
System.out.println("Dog 建構子");
}
}
new Dog();
// 輸出:
// Animal 建構子
// Dog 建構子
如果父類別沒有無參數建構子,必須明確呼叫 super():
public class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
}
public class Dog extends Animal {
public Dog(String name) {
super(name); // 必須呼叫
}
}
實際範例
// 父類別
public class Vehicle {
protected String brand;
protected int year;
public Vehicle(String brand, int year) {
this.brand = brand;
this.year = year;
}
public void start() {
System.out.println(brand + " is starting");
}
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 displayInfo() {
super.displayInfo();
System.out.println("Doors: " + doors);
}
public void honk() {
System.out.println("Beep!");
}
}
// 使用
Car myCar = new Car("Toyota", 2024, 4);
myCar.start(); // 繼承
myCar.displayInfo(); // 覆寫
myCar.honk(); // Car 專有
繼承的存取權限
| 父類別修飾詞 | 子類別可存取 |
|---|---|
| public | ✓ |
| protected | ✓ |
| default | 同套件才可以 |
| private | ✗ |
instanceof
檢查物件是否屬於某類別:
Dog dog = new Dog("Buddy");
System.out.println(dog instanceof Dog); // true
System.out.println(dog instanceof Animal); // true
System.out.println(dog instanceof Object); // true
Animal animal = new Animal("Generic");
System.out.println(animal instanceof Dog); // false
何時使用繼承
使用繼承的情況:
- 「是一種」(is-a) 關係:Dog is an Animal
- 需要重複使用父類別的程式碼
- 需要多型行為
避免繼承的情況:
- 「有一個」(has-a) 關係:Car has an Engine(使用組合)
- 只是想重用程式碼(考慮組合或委派)
// 繼承:Dog is an Animal
class Dog extends Animal { }
// 組合:Car has an Engine
class Car {
private Engine engine; // 組合
}