2016-10-11 5 views
10

Ich habe heute mit anonymen Klassen experimentiert. Wenn ich System.out.println(super.x); tue, druckt es 12, und wenn ich System.out.println(x); verwende, druckt es 4. Ich dachte super.x würde 4 drucken und fragte mich, ob jemand mir bitte erklären könnte, warum das ist?Anonyme Klassenvariablen

public class AnonClass { 

    private int x = 1; 

    public AnonClass(int x) { 
     this.x = x; 
    } 

    public static void main(String[] args) { 
     AnonClass test = new AnonClass(4); 
     test.testMethod(); 
    } 

    public void testMethod() { 

     AnonClass anon = new AnonClass(12) { 
      { 
       System.out.println(super.x); //Prints 12 
       System.out.println(x); //prints 4 
      } 
     }; 

    } 
} 
+0

Ich dachte, 'super' nur mit Vererbung verwendet wurde. Ich denke nicht. – Gendarme

+2

@Gandarme warum denkst du das? Anonyme Klassen erben von der Klasse, die sie erweitern. –

+0

@AndyTurner Nun, ich denke, mein Wissen in Java ist zu ... flach. Diese ganze Sache ist jenseits von mir. – Gendarme

Antwort

11

Wenn Sie eine anonyme Klasse wie folgt innerhalb class AnonClass definieren:

AnonClass anon = 
    new AnonClass(12) { 
     { 
     System.out.println(super.x); //Prints 12 
     System.out.println(x); //prints 4 
     } 
    }; 

der Compiler eine Klasse etwas wie folgt erstellen:

class AnonClass$1 extends AnonClass { 
    final AnonClass enclosed; 

    AnonClass$1(AnonClass enclosed, int x) { 
    super(x); 
    System.out.println(super.x); 
    System.out.println(enclosed.x); 
    this.enclosed = enclosed; 
    } 
} 

und dann rufen Sie es mögen:

AnonClass anon = new AnonClass$1(this, 12); 

Beachten Sie, dass der Aufruf des Superkonstruktors (super(x);) vor dem Inhalt des Instanzinitialisierers (den Zeilen System.out.println) erfolgt.

Als solches wird das Feld AnonClass.x bis 12 durch den Superkonstruktor initialisiert, und dann wird sein Wert als 12 über System.out.println(super.x); gedruckt.

Dann System.out.println(x) verweist tatsächlich die x in dem umschließenden Instanz AnonClass, deren Wert 4.

Der Grund ist es nicht 12 wieder nicht gedruckt ist, dass x ist private; und wie es in JLS Sec 8.2 heißt:

Mitglieder einer Klasse, die als privat deklariert werden, werden nicht von Unterklassen dieser Klasse geerbt.

So gibt es keine AnonClass$1.x zu drucken; Der einzige Bezeichner im Bereich x ist AnonClass.x.

+1

Welcher Teil der Java-Spezifikation besagt, dass ein nicht qualifizierter Bezeichner in einer anonymen Klasse in die umschließende Klasse und nicht in die anonyme Superklasse aufgelöst wird? Ich hätte einen "mehrdeutigen" Kompilierungsfehler erwartet. – Andreas

+0

Dies ist in der Tat eine interessante Frage - und noch ein Grund, die Doppelstrebeninitialisierung nicht zu verwenden. Ein Verweis auf die JLS bezüglich der Variablenauflösung in dem Instanzinitialisierer würde geschätzt werden. –

+2

Hier ist ein Tipp, um meine Frage zu beantworten, ich denke: Wenn Sie 'private' aus dem Feld' x' entfernen, beziehen sich sowohl 'super.x' als auch 'x' auf die Super-Instanz. Nur wenn "x" "privat" ist, bezieht sich das unqualifizierte "x" auf die umschließende Instanz. – Andreas

1

Sie haben zwei Klassen hier: reguläre Klasse AnonClass und anonyme Klasse AnonClass$1AnonClass

erstreckt Beiden Klassen haben x Feld

Sie haben auch zwei Objekte: ein vom Typ AnonClass mit x = 4 innerhalb main Methode instanziiert und zweiter Typ AnonClass$1 instanziiert innerhalb testMethod() mit x = 12

Wenn Sie den Wert super.x drucken, greifen Sie auf das Feld x des zweiten Objekts zu; aber der Wert von x gehört zu dem ersten Objekt führt, dass Sie Klasse nicht static und enthält eine implizite Bezugnahme auf Instanz von äußeren Klasse

Referenz: Nested Classes in Java