2013-03-04 19 views
16

Ich habe eine Outer Klasse, die eine private Inner Klasse hat.Java: private innere Klasse synthetisierte Konstruktoren

In meinem Outer Klassenmethode, instanziiert ich die Inner Klasse wie folgt:

Outer outer = new Outer(); 
Inner inner = outer.new Inner(); 

Der Compiler wandelt diesen Code:

Outer outer = new Outer(); 
Inner inner = new Inner(outer, null); 

Mit Reflexion zeigt, dass die Inner Klasse der synthetisierten hat folgende Erbauer:

private Outer$Inner(Outer) 
Outer$Inner(Outer,Outer$Inner) 

Da die Klasse Innerprivate ist, fügt der Compiler den Konstruktor private hinzu, damit niemand diese Klasse instanziieren kann. Aber offensichtlich sollte die Outer-Klasse in der Lage sein, es zu instantiieren, also fügt der Compiler dieses andere private Konstruktorpaket hinzu, das wiederum den privaten Konstruktor aufruft. Da der package-private Konstruktor den Namen $ in seinem Namen hat, kann der normale Java-Code ihn nicht aufrufen.

Frage: Warum einen privaten und einen Paket-privaten Konstruktor synthetisieren? Warum nicht nur den package-privaten Konstruktor synthetisieren und damit fertig werden?

+0

@Noofiz diese Konstruktoren werden vom Compiler erstellt, ohne dass Sie explizit für sie codieren; daher nannte ich sie synthetisiert. – shrini1000

+0

@Noofiz Wenn Sie die Frage nicht verstehen, schlage ich vor, Sie überlassen es denen, die es tun. – EJP

+0

Ist die Äußere $ Innere (Äußere, Äußere $ Innere) wirklich richtig? Der Konstruktor ruft eine Instanz derselben Klasse als Argument ab. Warum sollte der Compiler einen solchen Parameter hinzufügen? –

Antwort

13

Wenn Sie den Code schreiben, wie,

public class Outer { 
     private class Inner {} 
} 

Sie werden feststellen, dass es nur einen Konstruktor private Outer$Inner(Outer)

Dieser Konstruktor von 8.8.9 of the JLS Abschnitt erforderlich ist, die besagt, dass, wenn kein Konstruktor definiert eine Standard Konstruktor muss generiert werden, und in diesem Fall muss der Standardkonstruktor privat sein

In einer Klassenart, wenn die Klasse ist Öffentlich deklariert, dann erhält der Konstruktor implizit den Zugriffsmodifikator public (§6.6); Wenn die Klasse als geschützt deklariert ist, dann ist der Standardkonstruktor implizit gegeben der Zugriffsmodifizierer geschützt (§6.6); Wenn die Klasse als privat deklariert ist, erhält der Standardkonstruktor implizit den Zugriffsmodifikator private (§6.6) ; Andernfalls hat der Standardkonstruktor den Standardzugriff, der durch keinen Zugriffsmodifikator impliziert wird.

Wenn Sie jedoch eine Instanz von Inner innerhalb Outer mit Code instanziiert wie

public class Outer { 
    private class Inner {} 
     public String foo() { 
      return new Inner().toString(); 
     } 
} 

Der Compiler hat einen Konstruktor zu erzeugen, die Outer rechtlich nennen kann (Sie rechtlich nicht den privaten anrufen Standardkonstruktor, da es privat ist). Also muss ein neuer synthetischer Konstruktor vom Compiler generiert werden.Der neue Konstruktor muß synthetisch sein, entsprechend section 13.1 of the JLS

Jede vom Compiler eingeführten Konstrukte, die in dem Quellcode keine haben entsprechende konstruieren muß synthetische markiert werden, mit Ausnahme von Standardkonstruktoren und der Klasse Initialisierung Methode.

Dieser zweite Konstruktor hat kein entsprechendes Konstrukt im Quellcode, daher muss dieser neue Konstruktor synthetisch sein. Der erste private Konstruktor muss noch generiert werden, da die JLS einen privaten Standardkonstruktor benötigt.

+0

Warum ist es illegal, eine neue Instanz von Inner zu instanziieren? Outer kann es immer noch tun, oder? Da dieser private Konstruktor vom Compiler generiert wird, warum ist es dann kein synthetischer Konstruktor? – shrini1000

+0

Reworded meine Antwort. – sbridges

+0

Das ist jetzt klar. Danke! – shrini1000

2

Die wahrscheinlichste Antwort ist, zu respektieren, was Sie in Ihrem Quellcode deklariert haben. Dadurch können Sie weiterhin den privaten Konstruktor bei der Deklaration verwenden.

Dies vermeidet auch zu überprüfen, ob der private Konstruktor tatsächlich innerhalb der Inner Klasse aufgerufen wird.

3

Dies ist keine Antwort, die meiner Meinung nach gut von sbridges abgedeckt wurde. Es ist einfach ein funktionierendes Beispiel, das das von Ihnen beschriebene Verhalten erzeugt:

public class Outer { 
    private class Inner { 
    } 

    public static void main(String[] args) { 
     printConstructors(); 

     //only one constructor is printed but two would appear if you 
     //uncommented the line below 

     //new Outer().new Inner(); 
    } 

    private static void printConstructors() { 
     Constructor[] constructors = Outer.Inner.class.getDeclaredConstructors(); 
     for (Constructor c : constructors) { 
      System.out.println(c.toGenericString()); 
     } 
    } 
}