Die Lösung, um den Code kompilieren zu lassen, wird in alfasins Antwort behandelt.
Der Grund dafür ist, wie Java Typen ableitet.Java kann in bestimmten Fällen nur auf einen Typ schließen (siehe Dokumentation für weitere Details here, speziell den Abschnitt Target Types
).
Zitat aus dieser docs:
Note: It is important to note that the inference algorithm uses only invocation arguments, target types, and possibly an obvious expected return type to infer types. The inference algorithm does not use results from later in the program.
Das Problem mit dem Schnipsel kommt auf Typen durch Ziel Typinferenz und die Verwendung des Punkt-Operators zu Ketten Methoden abgeleitet. Wenn Sie den Punktoperator verwenden, wird das Ergebnis der ersten Methode zuerst für die zweite Methode verwendet (wird piped). Dies ändert also den Zieltyp, so dass es der Typ ist, der vom folgenden Teil nach dem Punkt erwartet wird. Es wird jedoch nur das Ergebnis der letzten Methode in der Kette von Methoden dem Variablentyp zugewiesen, und somit können die generischen Typen der letzten Methode in Ihrem Fall abgeleitet werden.
So im ersten Schnipsel, der Teil, wo der Typ abgeleitet werden muss, ist die letzte Methode nach dem Punkt-Operator, so dass der Zieltyp für diese Methode ist die Variable, auf die das Ergebnis zugewiesen werden soll und kann somit abgeleitet werden. d Vom ersten Schnipsel der Zeilen:
Outer.Inner<String> obj2 = new Outer().new Inner<>(); // fine !
Seit ‚neuen Outer()‘ ein Objekt zurückgibt, das nicht einen generischen Typen hat, braucht keine Folgerung auftreten. Die zweite Methode new Inner<>()
kann fortgesetzt werden. Das Ergebnis der Methode new Inner<>()
wird hier der Variablen obj2
zugewiesen, die den Typ Outer.Inner<String>
hat, und daher kann von ihrem Ziel abgeleitet werden, dass T
String
sein soll.
Im zweiten Ausschnitt ist der Teil, bei dem der Typ abgeleitet werden muss, die Methode vor dem Punktoperator. Dies bedeutet, dass das Ergebnis der ersten Methode auf die zweite Methode angewendet wird.
So von Ihrem zweiten Schnipsel der Zeilen:
Outer<String>.Inner obj2 = new Outer<>().new Inner();
Der Zieltyp von new Outer<>()
ist, was new Inner()
erwartet, was Outer<T>.newInner()
ist; Aufgrund von Type-Löschungen und der Funktionsweise von Java-Generics wird dieses T als Object
angesehen, da es nicht als ein bestimmter Typ angegeben ist. Nun kann der zweite Teil fortgesetzt werden, aber das Ergebnis der zweiten Methode ist jetzt vom Typ Outer<Object>.Inner
, der nicht in den zugewiesenen Typ der Variablen konvertiert werden kann.
Sie müssen also einen Typzeugen für die Methode angeben, d. H. new Outer<SomeMethod>()
, da im zweiten Snippet kein geeigneter Zieltyp vorhanden ist, um die Typinterferenzen so ausführen zu können, wie Sie möchten.
Ich bin mir nicht ganz sicher hier (hätte in der Spezifikation zu graben), aber ich nehme an, das ist wegen der Ausführungsreihenfolge und Typschlussfolgerung hier ein Problem. Was ich meine, ist, dass Typ-Inferenz den Typ von "obj2" als "Inner" und _maybe_ sogar als den äußeren Typ "Outer" sieht, aber da er zuerst eine Instanz von "Outer" erzeugen muss, die _nicht_ eine Instanz von 'Inner ist 'Schlußfolgerung schlägt fehl. Im Allgemeinen wurde die Art der Rückschlüsse über mehrere Codeebenen (kann auch Methodenaufrufe sein) mit jeder Java-Version verbessert, ist aber wahrscheinlich noch lange nicht perfekt. –
Thomas
WARUM würdest du diesen Code überhaupt schreiben? Wenn Sie sich für die Instantiierung der äußeren Klasse nicht interessieren, warum sollten Sie überhaupt eine innere Klasse benutzen? – EJP
@EJP Ich verstehe nicht, wie Sie daraus geschlossen haben, dass der OP die Instanziierung der äußeren Klasse nicht interessiert. In "Outer .Inner obj2 = new Outer <>(). New Inner();" sieht es so aus, als wolle er speziell, dass die äußere Klasse ein "Outer " ist. –
DodgyCodeException