Java基礎知識詳解: protected修飾符


@author: Tobin
Java初學者,試圖用最簡單的大白話讓自己搞懂一些知識點。

修飾符modifiers介紹

學習Java不可避免地接觸到一些基本的修飾符。
修飾符決定了類成員的訪問權限,是否能夠被其它類所訪問。

  • private: 只能被基類訪問
  • 無修飾符: 被基類,子類和同package的類訪問
  • protected: 在無修飾符的基礎上,加了與基類不同包,但是是子類的訪問權限,這個訪問權限只在子類訪問自身的實例時才有,超類的實例還是不能訪問的
  • public: 全都可以訪問

下面這個很好地展現了權限的逐層增加。

protected修飾符詳解

《Java編程思想》對protected的介紹是:被protected修飾的成員對於本包和其子類可見。看了上面的圖,我們知道子類可見的意思是不同包的子類也是可見的。總結一下就是:

  • 基類的protected成員是包內可見的
  • 當不在同一個包,但是是其子類也是可以訪問protected的成員的。但是有個前提,就是子類只能訪問其繼承來的protected成員,如果是在子類中初始化一個超類的實例,這個實例是無法訪問protected的成員的。
    概念比較抽象,用形象的語言來說。
    包就相當於一個家族。不同包有可能有繼承的分支,也有可能毫無關系。類內的成員就相當於資源。
  • private: 私有資源,只能自己使用
  • default: 家族,我自己,我子孫可以用
  • protected: 我可以開放,但是只給自己家族的但是嫁到或者入贅其它家族的后代使用
  • public: 誰都可以用,水資源

參考幾個例子,分析下。
(1)示例1

//示例一
package p1;
public class Father1 {
    protected void f() {} // 父類Father1中的protected方法
}

package p1;
public class Son1 extends Father1 {}

package p11;
public class Son11 extends Father1{}

package p1;
public class Test1 {
    public static void main(String[] args) {
        Son1 son1 = new Son1();
        son1.f(); // Compile OK ----(1)
        son1.clone(); // Compile Error ----(2)

        Son11 son = new Son11();    
        son11.f(); // Compile OK ----(3)
        son11.clone(); // Compile Error ----(4)
    }
}
  • f方法是超類Father1的,son1和son11雖然是定義不同的包,但是它們的都是Father1的子類,所以都可以訪問f方法。此外Test1也在p1包里,所以1和3編譯通過。
  • son1和son11的clone()方法都是來自於Father1,但是和f的區別在於,Father的clone()還來自於java.lang.Object,Test1也是Object的子類,這只是說明它可以訪問自己繼承的clone()方法,即使其它分支繼承了相同的方法,它也是不可以訪問的。想象一下,家族給其它分支都分配一些資源,即使是相同的,我也不該有權限去訪問其它分支的資源。

(2)示例2

//示例二
package p2;
class MyObject2 {
    protected Object clone() throws CloneNotSupportedException{
       return super.clone();
    }
}

package p22;
public class Test2 extends MyObject2 {
    public static void main(String args[]) {
       MyObject2 obj = new MyObject2();
       obj.clone(); // Compile Error ----(1)

       Test2 tobj = new Test2();
       tobj.clone(); // Complie OK ----(2)
    }
}
  • Test2繼承了MyObject2,clone()方法來源於MyObject2,Test2可以建立自身實例,然后訪問clone()方法,2通過
  • 但是作為子類,Test2建立超類實例,直接去訪問超類的protected方法是不可以的
  • 想一下,家族已經給我分支資源了,我還要直接向家族拿資源,不該有這個權限
    (3)示例3
//示例三
package p3;
class MyObject3 extends Test3 {
}

package p33;
public class Test3 {
  public static void main(String args[]) {
    MyObject3 obj = new MyObject3();
    obj.clone(); // Compile OK ------(1)
  }
}
  • MyObject3繼承Test3,兩個不在一個包內。Test3作為超類,建立了子類的一個實例,訪問子類繼承的來自於它的方法,當然它的clone()方法,也是繼承自java.lang.Object,這個不管,繼承自我的,我是有權限訪問的
  • 想象一下,家族給分支資源了,家族是有權限直接訪問我給出的資源的

(4)示例4

//示例四
package p4;
class MyObject4 extends Test4 {
  protected Object clone() throws CloneNotSupportedException {
    return super.clone();
  }
}

package p44;
public class Test4 {
  public static void main(String args[]) {
    MyObject4 obj = new MyObject4();
    obj.clone(); // Compile Error -----(1)
  }
}
  • 和示例3的區別在於,此時的clone()方法是子類自身的方法了,來源於MyObject4本身,作為超類是沒有權限訪問子類的protected成員的
  • 想象一下,分支建立自己的受保護資源,家族沒有權限直接訪問的
    (5)示例5
//示例五
package p5;

class MyObject5 {
    protected Object clone() throws CloneNotSupportedException{
       return super.clone();
    }
}
public class Test5 {
    public static void main(String[] args) throws CloneNotSupportedException {
       MyObject5 obj = new MyObject5();
       obj.clone(); // Compile OK ----(1)
    }
}
  • 現在屬於同一個包,Test5可以直接訪問Myobject5的protected成員
  • 想象一下,同一個家族的資源共享
    (6)示例6
//示例六
package p6;

class MyObject6 extends Test6{}
public class Test6 {
  public static void main(String[] args) {
    MyObject6 obj = new MyObject6();
    obj.clone(); // Compile OK -------(1)
  }
}
  • 即使不在同一個包,1也成立。此處在同一個包,且clone()方法來自於Test6
  • 同一個家族的資源共享
    (7)示例7
//示例七
package p7;

class MyObject7 extends Test7 {
    public static void main(String[] args) {
        Test7 test = new Test7();
        test.clone(); // Compile Error ----- (1)
  }
}

public class Test7 {}
  • 超類Test7的方法來自於java.lang.Object,只有java.lang這個包和對應繼承了這個clone()方法的Test7才能訪問。說白了,方法還是一個方法,但是被不同的子類繼承了,就不再是同樣的方法了。
  • 看起來是一個家族的,實際上資源是超類從其它家族得到的。其它家族對該資源做了限制,所以不能整個家族都能使用。其次,子類只能訪問自身實例的protected資源,沒有權限訪問超類實例的protected資源。兩個條件都不滿足。

其它修飾符

static
final
abstract
見我Java基礎知識系列的其它文章。

總結

protected成員,在相同package下,對其它類開放,不同package下,對繼承了該類的子類開放(有條件)。其它包的子類沒有權限直接創建超類的實例,然后訪問超類的protected成員。除了認清楚protected屬性,更重要的是要辨別來源,來源決定package是哪個,這是決定訪問權限的基礎。

參考文章
https://blog.csdn.net/ciawow/article/details/8262609。
https://blog.csdn.net/justloveyou_/article/details/61672133


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM