深刻理解 Java 中 protected 修飾符

看似簡單的東西能夠引出不少問題,學習過程當中不少概念咱們都只是「好像瞭解」、「貌似是這樣」、「應該沒問題」, 其實缺少的是仔細思考, 對本身少問了幾個「爲何」。java

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

在 《Thinking in Java》 中,protected 的名稱是「繼承訪問權限」,這也就是咱們記憶中的 protected:protected 必需要有繼承關係纔可以訪問。 因此你覺得你懂了, 但是你真的理解了這句話嗎?學習

先思考幾個問題:spa

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

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

  3. 不一樣包下, 在子類中建立父類對象能訪問父類的 protected 方法嗎?繼承

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

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

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

父類爲非靜態 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 修飾符的做用是沒法真正發現它的微妙。

相關文章
相關標籤/搜索