首先,必須明確Java中類成員的訪問修飾符(public、private、protect、默認或friendly等,C++也同理),並不能簡單的理解爲書上說的如“子類可以訪問”,具體因結合類的內存佈局圖來理解。例如一個父類有public a成員和protect b成員,在其子類的方法中訪問a時,要考慮子類的內存佈局能否看到a。 結合內存佈局圖就可以理解所謂“子類可以訪問父類的protect b成員”說的是指本子類繼承了父類的成員b,所以也具有b,當然就可以訪問了。對於private成員,子類不繼承,當然就沒有了。 對於public的東西,在任何地方都能找到,對於private和protect就看通過內存佈局能不能找到(即屬於自己的可以找到,不屬於自己的東西當然找不到了)。
【總之一句話,能不能訪問,就看在當前作用域下能不能找到。】
以下是原因分析:
在Core Java中有這樣一段話“在Object類中,clone方法被聲明爲protected,因此無法直接調用anObject.clone()。子類只能直接調用受保護的clone方法克隆它自己。爲此,必須重新定義clone方法,並將它聲明爲public,這樣才能讓所有的方法克隆對象”。但是不是所有的子類都可以訪問受保護的方法嗎?不是每個子類都是Object的之類嗎?下面就用例子來說明下protected訪問修飾符的問題。
在package1中創建SuperClass.java文件,裏面有一個protected方法,內容如下。
- package package1;
- public class SuperClass {
- protected void method(){
- System.out.println("This is a protected method in the super class .");
- }
- }
- package package1;
- public class SubClass1 extends SuperClass {
- public static void main(String[] args) {
- SuperClass sup = new SuperClass();
- SubClass1 sub1 = new SubClass1();
- SubClass2 sub2 = new SubClass2();
- sup.method(); //Compile OK
- sub1.method(); //Compile OK
- sub2.method(); //Compile OK
- }
- }
- class SubClass2 extends SuperClass{
- }
如果在另一個包package2中創建SubClass1.java文件,內容與包package1中的SubClass1.java內容相同。
- package package2;
- import package1.SuperClass;
- public class SubClass1 extends SuperClass {
- public static void main(String[] args) {
- SubClass1 sub1 = new SubClass();
- SubClass2 sub2 = new SubClass2();
- Sub1.method(); //Compile OK
- sub2.method(); //Compile Error
- }
- }
- class SubClass2 extends SuperClass{
- }
如果我們在package2中的SubClass2中重寫SuperClass的method方法。
- package package2;
- import package1.SuperClass;
- public class SubClass extends SuperClass {
- public static void main(String[] args) {
- SubClass sub = new SubClass();
- SubClass2 sub2 = new SubClass2();
- sub.method(); //Compile OK
- sub2.method(); //Compile OK
- }
- }
- class SubClass2 extends SuperClass{
- protected void method(){
- super.method();
- }
- }
如果我們在一個類中調用父類對象的protected方法會怎麼樣?
在package1中創建父類SuperClass.java文件,裏面有一個protected方法,內容如下。
- package package1;
- public class SuperClass {
- protected void method(){
- System.out.println("This is a protected method in the super class .");
- }
- }
在另一個包package中創建子類SubClass.java文件,內容如下。
- package package2;
- import package1.SuperClass;
- public class SubClass extends SuperClass {
- public static void main(String[] args) {
- SuperClass sup = new SuperClass();
- SubClass sub = new SubClass();
- sup.method(); //Compile Error
- sub.method(); //Compile OK
- }
- }
這裏我在SubClass繼承另一個包中的SuperClass,這個SuperClass中有一個protected方法method()。在SubClass類中調用SubClass類的實例sub的method()方法,編譯不會報錯。而同樣調用SuperClass類的實例sup的method()方法,編譯報錯!
protected方法不是可以被子類訪問的嗎?
從接觸Java開始就瞭解Java中訪問修飾符的權限可以用下面這個表格概括:
作用域 |
當前類 |
同包 |
子孫類(不同包) |
其他 |
---|---|---|---|---|
public |
Y |
Y | Y | Y |
protected |
Y |
Y |
Y |
N |
default |
Y |
Y |
N |
N |
private |
Y |
N |
N |
N |
現在必須明確的是:類SubClass確實是繼承了類SuperClass(包括它的method方法),所以在類SubClass中可以調用自己的method方法。但類SuperClass的protected方法對其不同包子類SubClass來說,是不可見的。
注意protected訪問修飾符的規則及其微妙。