2017-10-12 92 views
6

假設我們有兩個包p1p2p2.M12擴展類p1.M1如下:爲什麼包保護方法在同一個包中不可見?

package p1; 

public class M1 { 
    void method1() { 
     System.out.println("Method 1 called"); 
    } 
} 


package p2; 

import p1.M1; 

public class M12 extends M1 { 
    void method2() { 
     System.out.println("Method 2 called"); 
    } 
} 

讓我們延長M12p2.B

package p2; 

public class B extends M12 { 

    public void doSomething() { 
     method1(); 
     method2(); 
    } 
} 

這給出了一個編譯錯誤作爲method1,是套餐的p1內的保護在p2中不可見。 method2顯示沒有問題。

現在讓我們來延長p2.M12p1.A

package p1; 

import p2.M12; 

public class A extends M12 { 

    public void doSomething() { 
     method1(); 
     method2(); 
    } 
} 

在這裏我得到一個編譯錯誤,兩個method2()(這是可以理解的)method1()The method method1 from the type M1 is not visible

我的問題是:爲什麼是method1,它在封裝中受封裝保護p1在類別A中不可見,來自同一封裝p1

+0

這意味着一個孩子的班級會比其父母看到的多。這聽起來很奇怪。 – luk2302

+0

@ luk2302這個軟件包保護的方法不在包中,也很奇怪。 – lexicore

+0

這是我設法找到的JLS中最相關的部分:https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.12.4.3 –

回答

2

首先,什麼是類的成員?所述Java Language Specification狀態

類體可含有類的成員的聲明,即 是,字段(§8.3),方法(8.4節),類(第8.5節),和接口 (第8.5節) 。

它們是由什麼組成的?類類型的JLS states

成員是以下所有:

  • 成員繼承其直接超類(§8.1.4),除在類對象,其具有沒有直接超類
  • 從任何直接超接口繼承的成員(§8.1.5)
  • 成員在類的主體中聲明(§8.1.6)

它還提到

被聲明protectedpublic是 繼承通過在比在其它 一個包中聲明子類的一個類的成員才哪個類被聲明。

所有這一切都在chapter on Inheritance

其直接超改寫類C繼承超類的所有具體方法m (靜態和實例)對所有的 的以下爲真:

  • m是直接超級會員女士的C
  • mpublicprotected在包裹訪問中聲明與C`相同的包中。
  • C中聲明的任何方法的簽名都是m簽名的子簽名(第8.4.2節)。

M1類的成員是method1(和Object所有方法)。 M12,與其直接超類M1處於不同的包中,不繼承method1M12的成員因此只有method2

B的直接超類是M12並且在同一個包中。因此它繼承了其成員method2Bmethod1一無所知。如果您使用javac編譯了代碼,則應該收到編譯錯誤cannot find symbol。 (看來Eclipse正試圖猜測你在做什麼。)

同樣,A的直接超類M12,但是在不同的包中。由於這個原因,它不會繼承method2A不知道任何關於method1method2,因爲它沒有繼承它們。這兩個都是無法找到的符號。

+1

只是注意到,其他答案確實提到了這一點,這就是爲什麼我從Krease提出的原始內容,而且,這是後期是如何給出我的@override註釋示例的替代解釋,如果繼承是線性的過程,並且註釋應該指向這篇文章的引用:如果你已經用javac編譯你的代碼,你將會收到一個找不到符號編譯錯誤。 – Victor

1

可見性必須流過類層次結構。

的類層次結構是A --> M12 --> M1

的,因爲M1.method1是不可見的M12,這是不可見的,它的任何子類要麼,像A

+1

「可見性必須通過類層次結構。」 - 爲什麼? – lexicore

+0

「爲什麼」 - 這是語言的工作方式 - 是否值得挖掘定義此規範的規範,或僅僅瞭解「這是語言設計工作的方式」? – Krease

+0

如果你有方便的話,我會對spec中的指針感興趣。 –

3

我覺得要理解這種行爲的最簡單的方法是「A是M12」

當你聲明的繼承,你告訴你一個從M12獲得其行爲的想法,但M12沒有所謂看得見的方法方法1。

讓我們做一個實驗的樂趣:

public class M12 extends p1.M1 { 
    public void method1() { 
     System.out.println("Method 1 called"); 
    } 
    void method2() { 
     System.out.println("Method 2 called"); 
    } 
} 

忘記..當你聲明這樣的方法,它被允許 - 如果你沒有一個@覆蓋就可以了。 但是,如果M1是:

public class M1 { 
    public void method1() { 
     System.out.println("Method 1 called"); 
    } 
} 

你可以有:

public class M12 extends p1.M1 { 
    @Override 
    public void method1() { 
     System.out.println("Method 1 called"); 
    } 

    void method2() { 
     System.out.println("Method 2 called"); 
    } 
} 

現在,回到了M1和M2的原代碼與方法重新聲明,方法一個公開:

public class M12 extends p1.M1 { 
    public void method1() { 
     System.out.println("Method 1 called"); 
    } 

    public void method2() { 
     System.out.println("Method 2 called"); 
    } 
} 

然後,你就可以有

public class A extends M12 { 

    public void doSomething() { 
     method1(); 
     method2(); 
    } 
} 

好吧,這是一個微不足道的情況,但會失蹤,以完成序列...... 底線,從語義上說,你可以通過IS關係來解釋。


如果需要更多的(https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html):

下表顯示了訪問由每個改性劑允許成員。

訪問級別

Modifier Class Package Subclass World 

public  Y  Y  Y   Y 

protected Y  Y  Y   N 

no modifier Y  Y  N   N 

private  Y  N  N   N 
+0

您很容易忽略'A'也是*'M1'。 'M1'確實有一個方法'method1'在'p1'中可見。當然,我們可以讓所有的東西都公開,並考慮這個FTFY,但這不是問題所在。你引用了一個訪問級別的表 - 有「沒有修飾符 - 包Y」。 'A'與'M1.method1()'在同一個包中,所以解釋是什麼? – lexicore

+0

還要注意應該有所幫助的過度使用註釋行爲。 – Victor

+0

我沒有忽視。它似乎是同樣的情況,它屬於另一個答案,我贊成,因爲有人已經低估了它。這是一個奇怪的繼承情況 - 是A是M1,但它不是它從哪裏得到它的行爲,這是一種線性過程。我們可以在這裏談論一個子成員的訪問修飾符,因爲它在行爲上是相似的。假設你的子類擴展了方法的訪問級別。它的孩子的孩子將無法恢復原來的訪問級別,只能進一步擴展。奇怪的情況,如那些在深層次上會使繼承不好的奇怪情況。 – Victor

相關問題