2010-08-22 4 views
13

Ich möchte verstehen, was im folgenden Beispiel passiert (wo auf ein geschütztes Mitglied von außerhalb des Pakets durch eine Unterklasse zugegriffen wird).Java: geschützter Zugriff über Pakete hinweg

Ich weiß für Klassen außerhalb des Pakets, die Unterklasse kann das geschützte Mitglied nur durch Vererbung sehen. Es gibt zwei Pakete: package1 und 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 
        } 
    } 
    

Es versteht sich, dass die boo() Methode in ExtendsprotectedClassfoo() zugreifen können, können da geschützte Mitglieder nur durch Vererbung zugegriffen werden.

Meine Frage ist, warum die foo() Methode funktioniert gut, wenn in den main() Verfahren von ExtendsprotectedClass durch eine Referenz zugegriffen aber wird nicht, wenn durch die epc Referenz in UsesExtendedClass zugegriffen?

Antwort

12

Der Code innerhalb der ExtendsprotectedClass Klasse kann über eine Referenz vom Typ ExtendsprotectedClass auf geschützte Elemente von ProtectedClass zugreifen. Von den JLS section 6.6.2:

Geschütztes Elemente oder Konstruktor eines Objekts kann von außerhalb des Gehäuses zugegriffen werden kann, in der es nur durch Code deklariert wird, die für die Durchführung dieser Aufgabe verantwortlich ist.

und

sei C die Klasse, in der ein geschütztes Mitglied m deklariert wird. Zugriff erlaubt ist nur innerhalb des Körpers einer Unterklasse S von C. Wenn zusätzlich Id bezeichnet ein Instanzenfeld oder Instanzmethode, dann gilt:

  • Wenn der Zugriff durch einen qualifizierten Namen Q.Id ist, wobei Q wenn ein ExpressionName, so wird der Zugriff erlaubt, und nur, wenn der Typ des Ausdrucks Q S oder eine Unterklasse von S. [...]

UsesExtendedClass ist nicht für die Durchführung der ExtendsprotectedClass reponsible, Daher schlägt der letzte Aufruf fehl.

EDIT: Der Grund dafür ist, dass protected Zugriff wurde entworfen, um Unterklassen zu helfen, die Funktionalität, die sie benötigen, mehr Zugriff auf die Interna der Oberklasse zu implementieren, als normalerweise verfügbar wäre.Wenn das für alle Code verfügbar wäre, wäre es ziemlich nahe, die Methode öffentlich zu machen. Grundsätzlich wird den Unterklassen vertraut, die Einkapselung nicht zu unterbrechen; Sie erhalten mehr Möglichkeiten in Objekten ihres eigenen Typs. Die öffentliche API sollte diese Details nicht offen legen, aber die geschützte API kann nur dazu dienen, Unterklassen mehr Möglichkeiten zu geben.

+0

@ Jon Danke. Ich verstehe, dass Klassenmitglieder der Unterklasse auf geschützte Mitglieder zugreifen können (wie in der 'boo()' Methode angegeben). Aber war es neugierig zu wissen, warum es erlaubt ist, über eine Referenz der Unterklasse ** NUR ** in Unterklassenmethoden auf das geschützte Mitglied zuzugreifen? irgendwelche Gründe dahinter? – JWhiz

+0

@JWhiz: Bearbeiten ... –

+1

2) Funktioniert, weil auf die geschützte Methode von einem Zeiger seiner eigenen Klasse zugegriffen wird. Dies sollte fehlschlagen:
öffentliche statische void ExtendprotectedClass.main (String [] args) { ProtectedClass epc = neue ExtendprotectedClass(); // upcast
epc.foo(); // sollte Kompilierungsfehler sein?
} –

1

Ich glaube, Sie haben Ihre eigene Frage beantwortet; UsesExtendedClass erbt nicht von ProtectedClass, und - definitionsgemäß - sind "geschützte" Member nur in der Klasse verfügbar, in der sie deklariert sind, oder in einer Klasse, die von der Klasse erbt, in der sie deklariert oder definiert sind.

+2

'per Definition -" geschützte "Mitglieder sind nur in der Klasse zugänglich, in der sie deklariert/definiert sind. Ich bin nicht ganz damit einverstanden, da geschützte Mitglieder aus anderen Klassen innerhalb des gleichen Pakets ohne Vererbung zugänglich sind. – JWhiz

2

Es funktioniert im ersten Fall, weil es aus der gleichen Klasse aufgerufen wird, auch wenn auf die Methode über eine Referenz zugegriffen wird. Sie könnten sogar eine private Methode von ExtendsprotectedClass über eine Referenz in derselben Hauptmethode aufrufen.

+1

Danke. Jetzt sehe ich, warum es durch Referenz darauf zugreifen kann. '+ 1' dafür. Aber es sollte nicht erlaubt sein, 'private' Methoden über ein Objektreferenzrecht aufzurufen? Verstößt das nicht gegen den eigentlichen Zweck, es "privat" zu machen? Gibt es einen bestimmten Grund dafür? – JWhiz

+1

@JWhiz die Java-Zugriffsmodifizierer arbeiten auf Klasse und nicht auf Instanzenebene. Aus diesem Grund ist eine private Methode für die Klasse und nicht für eine Instanz privat. Wenn privat an Instanzen gearbeitet wird, müssten Sie mehr Variablen und Methoden veröffentlichen, wenn zwei Instanzen interagieren müssen. Dies würde die Einkapselung unterbrechen, indem die Implementierung außerhalb der Klasse sichtbar gemacht wird. – josefx