2013-08-28 48 views
22

我已經看到有關保護程序包和程序包專用修飾符之間差異的各種文章。有一件事我這兩個職位Java中的受保護和程序包專用訪問修飾符之間的區別?

  1. Isn't "package private" member access synonymous with the default (no-modifier) access?

    在這之間找到矛盾的接受的答案說,

    protected修飾符指定的成員只能在其自己的包內訪問(與包私有一樣),另外還有另一個包中的類的子類。

  2. Why the protected modifier behave differently here in Java subclass?

    在此接受的答案說,

    爲了滿足保護級別的訪問兩個條件必須滿足:

    • 的類必須在同一個包。
    • 必須有一個繼承關係。

他們不是矛盾嗎?從我對其他文章的理解,第一篇文章給出了正確答案,在其他包中保護== package-private + subclass。

如果這種說法是正確的,那麼爲什麼這個代碼失敗,我的子類貓以下錯誤消息在第17行

The method testInstanceMethod() from the type Animal is not visible 

我超和子類代碼如下。

package inheritance; 

public class Animal { 

    public static void testClassMethod() { 
     System.out.println("The class" + " method in Animal."); 
    } 
    protected void testInstanceMethod() { 
     System.out.println("The instance " + " method in Animal."); 
    } 
} 

package testpackage; 

import inheritance.Animal; 

public class Cat extends Animal{ 
     public static void testClassMethod() { 
      System.out.println("The class method" + " in Cat."); 
     } 
     public void testInstanceMethod() { 
      System.out.println("The instance method" + " in Cat."); 
     } 

     public static void main(String[] args) { 
      Cat myCat = new Cat(); 
      Animal myAnimal = myCat; 
      myAnimal.testClassMethod(); 
      myAnimal.testInstanceMethod(); 
     } 
    } 

請說明爲什麼上面的代碼失敗。這將是非常有用的。由於

+1

你必須是使用testInstanceMethod()的Cat。 Casting to Animal將對該方法的訪問權限限制在包lavel中,並且由於您的main在不同的包中,代碼將失敗。 (我認爲它甚至不會編譯)。是的,方法在那裏,但你沒有權限訪問它,因爲它是在Animal中被保護的。 – PSIXO

+0

第二個陳述應該被表述爲:*「爲了滿足受保護的級別訪問,**必須滿足**兩個條件之一......」*(另請參閱我在該答案下面做出的評論。) – aioobe

回答

21

第一個答案基本上是正確的 - protected成員可以通過

  • 類都是從同一個包的聲明類的
  • 子從其他包

但是訪問時,有一個小技巧:

6.6.2有關受保護訪問的詳細信息

對象的受保護成員或構造函數可以從僅在負責實現該對象的代碼聲明的包之外訪問。

這意味着,從其他包的子類不能訪問其超類的任意實例protected成員,他們只能訪問他們自己的類型的實例(其中類型是表達的編譯時類型,因爲它是一個編譯時檢查)。

例如(假設這個代碼是在Cat):

Dog dog = new Dog(); 
Animal cat = new Cat(); 

dog.testInstanceMethod(); // Not allowed, because Cat should not be able to access protected members of Dog 
cat.testInstanceMethod(); // Not allowed, because compiler doesn't know that runtime type of cat is Cat 

((Cat) cat).testInstanceMethod(); // Allowed 

這是有道理的,因爲通過CatDogprotected成員訪問可能會斷裂的Dog不變量,而Cat可以訪問它自己的protected成員安全,因爲它知道如何確保自己的不變量。

詳細規則:

6.6.2.1訪問受保護的成員

令C是其中一個受保護的成員M被聲明的類。如果Id表示實例字段或實例方法,則:

  • 如果訪問是通過限定名Q.Id,其中Q是一個表達式名稱,那麼當且僅當表達式Q的類型是S或S的一個子類時允許訪問。
  • 如果訪問是通過字段訪問表達式E.Id,其中E是主表達式,或者通過方法調用表達式E.Id(...)(其中E是主表達式),則當且僅當E的類型是S或S的子類時允許訪問。

6.6.2.2受保護的構造

讓C認證的訪問是在一個受保護的構造函數聲明的類和令S是在最裏面的類,它的聲明中使用了受保護的構造的發生。然後:

  • 如果接入是由一個超類構造函數調用超級或形式E.super的合格超類構造函數調用,其中E是一個主要表達式,則(。)(。)訪問被允許。
  • 如果訪問是通過形式爲new C(...){...}的匿名類實例創建表達式或由形式爲E.new的限定類實例創建表達式C(...){ ...},其中E是主表達式,則允許訪問。否則,如果訪問是通過一個簡單的類實例創建表達式的形式new C(...)或由一個限定的類實例創建的表達式形式爲E.new C(...),其中E是一個主表達式,那麼訪問是不被允許的。受保護的構造函數只能由定義它的包中的類實例創建表達式(它不會聲明匿名類)訪問。

參見:

+0

我想我理解,但仍需要一些時間來消化和理解。當覆蓋時,我們是否必須維護方法簽名,包括訪問修飾符的方法簽名?看來,如果超類具有'protected void get(){}'並且覆蓋它的子類不能具有'void get(){} ,即默認訪問。但它可以具有'public void get(){}'或'protected void get(){}' – eagertoLearn

+2

@ertortoLearn - 它背後的想法是一個子類,可以使方法更易於訪問,但不易訪問;這樣子類仍然符合超級合同。換句話說,投給超級球員永遠不應該讓你獲得更多的方法。 –

0

您已經創建了一個貓實例,並將其轉換爲它的超類類型,即動物類型。按照Animal類型,它的testInstanceMethod在相同的包或任何子類型中都可見。如果你沒有投入動物類型的代碼將編譯。

希望幫助

./Arun

1

在保護訪問的成員在同一個包訪問,並且在另一個包繼承的類成員也可以訪問。

在包訪問中,可以訪問同一包中類的成員。其他包中的類成員不能通過包訪問進行訪問。

+2

這個問題已經超過三年了,已經接受了答案。你的回答也沒有爲已經接受的答案增加任何有價值的東西,所以我不認爲你答案中的一個觀點在這裏(沒有冒犯)。 – rayryeng

相關問題