看似簡單的東西能夠引出不少問題,學習過程當中不少概念咱們都只是「好像瞭解」、「貌似是這樣」、「應該沒問題」, 其實缺少的是仔細思考, 對本身少問了幾個「爲何」。java
在 Java 中, 訪問權限修飾符屬於最最基礎的知識, protected 修飾符只是其中一個, 若是你要問爲何不拿 public、default、private 來深究呢? 那麼看完這篇文章你會知道爲什麼 protected 更值得深刻️思考。bash
在 《Thinking in Java》 中,protected 的名稱是「繼承訪問權限」,這也就是咱們記憶中的 protected:protected 必需要有繼承關係纔可以訪問。 因此你覺得你懂了, 但是你真的理解了這句話嗎?學習
先思考幾個問題:spa
同一個包中, 子類對象能訪問父類的 protected 方法嗎?code
不一樣包下, 在子類中建立該子類對象能訪問父類的 protected 方法嗎?對象
不一樣包下, 在子類中建立父類對象能訪問父類的 protected 方法嗎?繼承
不一樣包下, 在子類中建立另外一個子類的對象能訪問公共父類的 protected 方法嗎?get
父類 protected 方法加上 static 修飾符又會如何呢?編譯器
《Thinking in Java》中有一句話:「protected 也提供包訪問權限, 也就是說,相同包內的其餘類能夠訪問 protected元素」, 其實就是 protected 修飾符包含了 default 默認修飾符的權限, 因此第 1 個問題你已經知道答案了, 在同一個包中, 普通類或者子類均可以訪問基類的 protected 方法。string
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的靜態變量, 在子類中能夠直接訪問, 在不一樣包的非子類中則不可訪問
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 修飾符的做用是沒法真正發現它的微妙。