2010-08-22 10 views
13

Chciałbym zrozumieć, co dzieje się w poniższym przykładzie (gdzie chroniony członek jest uzyskiwany z zewnątrz pakietu przez podklasę).Java: chroniony dostęp przez pakiety

Wiem dla klas poza pakietem, podklasa może zobaczyć chronionego członka tylko przez dziedziczenie.

Istnieją dwa pakiety: package1 i package2.

  1. package1: ProtectedClass.java

    package org.test.package1; 
    
    public class ProtectedClass { 
    
        protected void foo() { 
         System.out.println("foo"); 
        } 
    } 
    
  2. package2: ExtendsprotectedClass.java

    package org.test.package2; 
    
    import org.test.package1.ProtectedClass; 
    
    public class ExtendsprotectedClass extends ProtectedClass { 
    
        public void boo() { 
         foo(); // This works, 
           // since protected method is visible through inheritance 
        } 
    
        public static void main(String[] args) { 
         ExtendsprotectedClass epc = new ExtendsprotectedClass(); 
         epc.foo(); // Why is this working? 
            // Since it is accessed through a reference, 
            // foo() should not be visible, right? 
        } 
    } 
    
  3. package2: UsesExtendedClass.java

    package org.test.package2; 
    
    public class UsesExtendedClass { 
    
        public static void main(String[] args) { 
         ExtendsprotectedClass epc = new ExtendsprotectedClass(); 
         epc.foo(); // CompilationError: 
            // The method foo() from the type ProtectedClass 
            // is not visible 
        } 
    } 
    

Zrozumiałe jest, że sposób w ExtendsprotectedClassboo() mogą uzyskać dostęp foo(), ponieważ członkowie chronione mogą być dostępne tylko w drodze dziedziczenia.

Moje pytanie brzmi, dlaczego metoda foo() działa dobrze, gdy dostęp poprzez odniesienie w sposobie ExtendsprotectedClass ale main() nie zadziała gdy dostępne poprzez odniesienie w UsesExtendedClassepc?

Odpowiedz

12

Kod w ramach klasy ExtendsprotectedClass może uzyskiwać dostęp do chronionych członków ProtectedClass przez odwołanie do typu ExtendsprotectedClass. Od JLS section 6.6.2:

można otworzyć chroniony członek lub konstruktor obiektu z zewnątrz opakowania, w którym została zadeklarowana tylko za pomocą kodu, który jest odpowiedzialny za realizację tego obiektu.

i

Niech C będzie klasa, w którym chroniony członek m jest zadeklarowana. Dostęp jest dozwolony tylko w obrębie korpusu podklasy S C. Ponadto, jeśli identyfikator oznacza pole sposób wystąpienia lub wystąpienie, a następnie:

  • Jeżeli dostęp jest przez nazwę Q.Id kwalifikowaną, w którym Q oznacza ExpressionName, wówczas dostęp jest dozwolone tylko wtedy, gdy typ ekspresji Q oznacza S lub podklasę S. [...]

UsesExtendedClass winny jest nie do realizacji ExtendsprotectedClass, stąd ostatnie połączenie nie udaje się.

EDYCJA: Przyczyną tego jest to, że dostęp protected ma na celu pomóc podklasom w implementacji potrzebnej im funkcjonalności, dając większy dostęp do wewnętrznych cech nadklasy, niż byłby normalnie dostępny.Gdyby było to dostępne dla kodu , byłoby całkiem blisko upublicznienia tej metody. Zasadniczo, podklasy ufają, że nie przerywają enkapsulacji; mają więcej możliwości w obrębie obiektów własnego typu. Publiczny interfejs API nie powinien ujawniać tych szczegółów, ale chroniony interfejs API może tylko w celu nadania podklasom więcej możliwości.

+0

@Jon Dzięki. Rozumiem, że członkowie klasy podklasy mają dostęp do chronionych członków (jak wskazano w metodzie 'boo()'). Ale był ciekawy wiedzieć, dlaczego jest dozwolony dostęp do chronionego członka poprzez odwołanie do podklasy, ** TYLKO ** w metodach podklasy? jakiekolwiek uzasadnienie tego? – JWhiz

+0

@JWhiz: Edytowanie ... –

+1

2) Działa, ponieważ ponieważ metoda chroniona jest dostępna przez wskaźnik własnej klasy. Powinno to zawieść:
Publiczna pustka statyczna ExtendsprotectedClass.main (String [] args) { ProtectedClass epc = new ExtendsprotectedClass(); // upcast
epc.foo(); // powinien być błąd kompilacji?
} } –

1

Wierzę, że odpowiedziałeś na własne pytanie; UsesExtendedClass nie dziedziczy po ProtectedClass i - z definicji - "chronione" elementy są dostępne tylko w klasie, w której są zadeklarowane/zdefiniowane lub należą do klasy dziedziczącej po klasie, w której są zadeklarowane lub zdefiniowane.

+2

"z definicji - członkowie" chronieni "są dostępni tylko w klasie, w której są zadeklarowani/zdefiniowani". Nie zgadzam się z tym, ponieważ chronieni członkowie są dostępni z innych klas w ramach tego samego pakietu bez dziedziczenia. – JWhiz

2

Działa w pierwszym przypadku, ponieważ jest wywoływana z tej samej klasy, nawet gdy metoda jest dostępna za pośrednictwem odwołania. Można nawet wywołać metodę private z poziomu ExtendsprotectedClass za pośrednictwem odwołania w tej samej głównej metodzie.

+1

Dzięki. Teraz widzę, dlaczego jest on w stanie uzyskać do niego dostęp poprzez referencję. "+ 1" za to. Ale, nie powinno być dozwolone wywoływanie "prywatnych" metod poprzez prawo do obiektu odniesienia? Czy nie narusza to samego celu uczynienia go "prywatnym"? Jakiś konkretny powód, dla którego można to zrobić? – JWhiz

+1

@ JWhiz modyfikatory dostępu do java działają na poziomie klasy, a nie na poziomie instancji. Z tego powodu prywatna metoda jest prywatna dla klasy, a nie dla instancji. Jeśli prywatny pracował nad instancjami, musiałbyś udostępnić więcej zmiennych i metod jako publiczne, gdyby dwie instancje musiały współdziałać. Spowoduje to przerwanie enkapsulacji przez uczynienie implementacji widoczną poza klasą. – josefx

Powiązane problemy