Java 基礎之繼承
阿新 • • 發佈:2020-12-04
訪問許可權
Java中,可以使用訪問控制符來保護對類、變數、方法和構造方法的訪問。Java 支援 4 種不同的訪問許可權。
- default (即預設,什麼也不寫): 在同一包內可見,不使用任何修飾符。使用物件:類、介面、變數、方法。
- private : 在同一類內可見。使用物件:變數、方法。 注意:不能修飾類(外部類)
- public : 對所有類可見。使用物件:類、介面、變數、方法
- protected : 對同一包內的類和所有子類可見。使用物件:變數、方法。 注意:不能修飾類(外部類)。
請注意以下方法繼承的規則:
- 父類中宣告為 public 的方法在子類中也必須為 public。
- 父類中宣告為 protected 的方法在子類中要麼宣告為 protected,要麼宣告為 public,不能宣告為 private。
- 父類中宣告為 private 的方法,不能夠被繼承。
抽象類與介面
1. 抽象類
抽象類和抽象方法都使用 abstract 關鍵字進行宣告。如果一個類中包含抽象方法,那麼這個類必須宣告為抽象類。
抽象類和普通類最大的區別是,抽象類不能被例項化,只能被繼承。
public abstract class AbstractClassDemo { protected int x; private int y; public abstract void func1(); public void func2() { System.out.println("func2"); } }
public class AbstractExtendClassDemo extends AbstractClassDemo {
@Override
public void func1() {
System.out.println("func1");
}
}
// AbstractClassDemo ac1 = new AbstractClassDemo(); // 'AbstractClassDemo' is abstract; cannot be instantiated AbstractClassDemo ac2 = new AbstractExtendClassDemo(); ac2.func1();
2. 介面
介面是抽象類的延伸,在 Java 8 之前,它可以看成是一個完全抽象的類,也就是說它不能有任何的方法實現。
從 Java 8 開始,介面也可以擁有預設的方法實現,這是因為不支援預設方法的介面的維護成本太高了。在 Java 8 之前,如果一個介面想要新增新的方法,那麼要修改所有實現了該介面的類,讓它們都實現新增的方法。
介面的成員(欄位 + 方法)預設都是 public 的,並且不允許定義為 private 或者 protected。
介面的欄位預設都是 static 和 final 的。
public interface InterfaceExample {
void func1();
default void func2(){
System.out.println("func2");
}
int x = 123;
// int y; // Variable 'y' might not have been initialized
public int z = 0; // Modifier 'public' is redundant for interface fields
// private int k = 0; // Modifier 'private' not allowed here
// protected int l = 0; // Modifier 'protected' not allowed here
// private void fun3(); // Modifier 'private' not allowed here
}
public class InterfaceImplementExample implements InterfaceExample {
@Override
public void func1() {
System.out.println("func1");
}
}
// InterfaceExample ie1 = new InterfaceExample(); // 'InterfaceExample' is abstract; cannot be instantiated
InterfaceExample ie2 = new InterfaceImplementExample();
ie2.func1();
System.out.println(InterfaceExample.x);
3. 比較
- 從設計層面上看,抽象類提供了一種 IS-A 關係,需要滿足裡式替換原則,即子類物件必須能夠替換掉所有父類物件。而介面更像是一種 LIKE-A 關係,它只是提供一種方法實現契約,並不要求介面和實現介面的類具有 IS-A 關係。
- 從使用上來看,一個類可以實現多個介面,但是不能繼承多個抽象類。
- 介面的欄位只能是 static 和 final 型別的,而抽象類的欄位沒有這種限制。
- 介面的成員只能是 public 的,而抽象類的成員可以有多種訪問許可權。
4. 使用選擇
使用介面:
- 需要讓不相關的類都實現一個方法,例如不相關的類都可以實現 Comparable 介面中的 compareTo() 方法;
- 需要使用多重繼承。
使用抽象類:
- 需要在幾個相關的類中共享程式碼。
- 需要能控制繼承來的成員的訪問許可權,而不是都為 public。
- 需要繼承非靜態和非常量欄位。
在很多情況下,介面優先於抽象類。因為介面沒有抽象類嚴格的類層次結構要求,可以靈活地為一個類新增行為。並且從 Java 8 開始,介面也可以有預設的方法實現,使得修改介面的成本也變的很低。
super
- 訪問父類的建構函式:可以使用 super() 函式訪問父類的建構函式,從而委託父類完成一些初始化的工作。應該注意到,子類一定會呼叫父類的建構函式來完成初始化工作,一般是呼叫父類的預設建構函式,如果子類需要呼叫父類其它建構函式,那麼就可以使用 super() 函式。
- 訪問父類的成員:如果子類重寫了父類的某個方法,可以通過使用 super 關鍵字來引用父類的方法實現。
public class SuperExample {
protected int x;
protected int y;
public SuperExample(int x, int y) {
this.x = x;
this.y = y;
}
public void func() {
System.out.println("SuperExample.func()");
}
}
public class SuperExtendExample extends SuperExample {
private int z;
public SuperExtendExample(int x, int y, int z) {
super(x, y);
this.z = z;
}
@Override
public void func() {
super.func();
System.out.println("SuperExtendExample.func()");
}
}
SuperExample e = new SuperExtendExample(1, 2, 3);
e.func();
SuperExample.func()
SuperExtendExample.func()
重寫與過載
1. 重寫(Override)
存在於繼承體系中,指子類實現了一個與父類在方法宣告上完全相同的一個方法。
為了滿足裡式替換原則,重寫有以下三個限制:
- 子類方法的訪問許可權必須大於等於父類方法;
- 子類方法的返回型別必須是父類方法返回型別或為其子型別。
- 子類方法丟擲的異常型別必須是父類丟擲異常型別或為其子型別。
重寫方法呼叫的優先順序如下:
- this.func(this)
- super.func(this)
- this.func(super)
- super.func(super)
2. 過載(Overload)
在同一個類中,指一個方法與已存在的方法名稱相同,但是引數型別、個數、順序至少一個不同。
注意:返回值不同,其他都相同不算數過載。