深入理解Java中protected修飾符

NO IMAGE

看似簡單的東西可以引出很多問題,學習過程中很多概念我們都只是「好像瞭解」、「貌似是這樣」、「應該沒問題」, 其實缺乏的是仔細思考, 對自己少問了幾個「為什麼」。

在 Java 中, 訪問權限修飾符屬於最最基礎的知識, protected 修飾符只是其中一個, 如果你要問為什麼不拿 public、default、private 來深究呢? 那麼看完這篇文章你會知道為何 protected 更值得深入️思考。

在 《Thinking in Java》 中,protected 的名稱是「繼承訪問權限」,這也就是我們記憶中的 protected:protected 必須要有繼承關係才能夠訪問。 所以你以為你懂了, 可是你真的理解了這句話嗎?

先思考幾個問題:

  1. 同一個包中, 子類對象能訪問父類的 protected 方法嗎?

  2. 不同包下, 在子類中創建該子類對象能訪問父類的 protected 方法嗎?

  3. 不同包下, 在子類中創建父類對象能訪問父類的 protected 方法嗎?

  4. 不同包下, 在子類中創建另一個子類的對象能訪問公共父類的 protected 方法嗎?

  5. 父類 protected 方法加上 static 修飾符又會如何呢?

《Thinking in Java》中有一句話:「protected 也提供包訪問權限, 也就是說,相同包內的其他類可以訪問 protected元素」, 其實就是 protected 修飾符包含了 default 默認修飾符的權限, 所以第 1 個問題你已經知道答案了, 在同一個包中, 普通類或者子類都可以訪問基類的 protected 方法。

父類為非靜態 protected 修飾類

package com.protectedaccess.parentpackage;
public class Parent {
protected String protect = "protect field";
protected void getMessage(){
System.out.println("i am parent");
}
}

不同包下,在子類中通過父類引用不可以訪問其 protected 方法

無論是創建 Parent 對象還是通過多態創建 Son1 對象, 只要 Parent 引用, 則不可訪問, 編譯器會提示錯誤。

package com.protectedaccess.parentpackage.sonpackage1;
import com.protectedaccess.parentpackage.Parent;
public class Son1 extends Parent{
public static void main(String[] args) {
Parent parent1 = new Parent();
// parent1.getMessage();   錯誤
Parent parent2 = new Son1();
// parent2.getMessage();  錯誤
}
}

不同包下,在子類中通過該子類引用可以訪問其 protected 方法

子類中實際上把父類的方法繼承下來了, 可以通過該子類對象訪問, 也可以在子類方法中直接訪問, 還可以通過 super 關鍵字調用父類中的該方法。

package com.protectedaccess.parentpackage.sonpackage1;
import com.protectedaccess.parentpackage.Parent;
public class Son1 extends Parent{
public static void main(String[] args) {
Son1 son1 = new Son1();
son1.getMessage(); // 輸出:i am parent,
}
private void message(){
getMessage();  // 如果子類重寫了該方法, 則輸出重寫方法中的內容
super.getMessage(); // 輸出父類該方法中的內容
}
}

不同包下,在子類中不能通過另一個子類引用訪問共同基類的 protected 方法

package com.protectedaccess.parentpackage.sonpackage2;
import com.protectedaccess.parentpackage.Parent;
public class Son2 extends Parent {
}

注意是 Son2 是另一個子類, 在 Son1 中創建 Son2 的對象是無法訪問父類的 protected 方法的

package com.protectedaccess.parentpackage.sonpackage1;
import com.protectedaccess.parentpackage.Parent;
import com.protectedaccess.parentpackage.sonpackage2.Son2;
public class Son1 extends Parent{
public static void main(String[] args) {
Son2 son2 = new Son2();
// son2.getMessage(); 錯誤
}
}

父類為靜態 protected 修飾類

對於protected的靜態變量, 在子類中可以直接訪問, 在不同包的非子類中則不可訪問

package com.protectedaccess.parentpackage;
public class Parent {
protected String protect = "protect field";
protected static void getMessage(){
System.out.println("i am parent");
}
}

靜態方法直接通過類名訪問

無論是否同一個包,在子類中均可直接訪問

package com.protectedaccess.parentpackage.sonpackage1;
import com.protectedaccess.parentpackage.Parent;
public class Son3 extends Parent{
public static void main(String[] args) {
Parent.getMessage(); // 輸出: i am parent
}
}

在不同包下,非子類不可訪問

package com.protectedaccess.parentpackage.sonpackage1;
import com.protectedaccess.parentpackage.Parent;
public class Son4{
public static void main(String[] args) {
// Parent.getMessage(); 錯誤
}
}

看到這裡你應該知道有多少種情況了, 針對不同的情況都可能出現意外的結果, 所以還是得多實踐, 僅僅在書上看一遍 protected 修飾符的作用是無法真正發現它的微妙。

相關文章

jsonserver的實踐與自定義配置化

快速排序js實現

SpringBoot如何通過SecurityContext緩存賬號密碼

平淡的秋招之路