Generic specification
Bevor ich auf die Instanziierung Probleme gehe ich Ihre allgemeinen revidieren definition:
Outer1<E extends Outer1<E>.Inner1>
Outer1 sollte im Grunde Elemente des Typs Inner1 oder alle untergeordneten Klassen davon enthalten. Deshalb ist die Art des Outer1 Objekt ist nicht von Bedeutung und kann mit dem folgenden Code ersetzt werden:
Outer1<E extends Outer1<?>.Innter1>
Auch haben die Verlängerungs Klassen wurden unter Verwendung der oben genannten leicht modifiziert.
Instanziierung
Für die Instanziierung von Objekten angegeben Sie wie folgt vor:
Outer1<Outer1.Inner1> a1; // WARNING: Outer1.Inner1 is a raw type
a1 = new Outer1<Outer1.Inner1>(); // WARNING: Outer1.Inner1 is a raw type
Wie newacct bereits erwähnt wurde, Outer1
wird mit einem generischen Typ deklariert wenn Sie nicht taten Geben Sie bei der Instanziierung des Objekts eine beliebige Zahl an.
Outer1<Outer1<?>.Innter1> a1; // or simply Outer1<?> a1;
a1 = new Outer1<Outer1<?>.Innter1>(); // or simply a1 = new Outer1<>();
Ähnliche für die Zuordnung von Klassen, die eine Basisklasse auf eine Art von dieser Basisklasse erweitert: Der Code sollte daher auf den folgenden geändert werden.
Sie geben mit der generischen Typdefinition an, welche Art von Elementen die Instanz enthalten soll.
Eine Erklärung wie
Outer1<Outer1<?>.Innter1> test;
werden alle Instanzen akzeptieren Outer1
erstreckt, die auch den generischen Typ entsprechen.Dies bedeutet, dass Sie nur
test = new Outer1<Outer1<?>.Inner1>();
test = new Outer2<Outer2<?>.Inner1>();
zuordnen können, aber nicht Outer3
oder sogar Outer4
!
Auch wenn Sie den Code weiter modifizieren, um z.
public static class Outer5<E extends Outer1<?>.Inner1> extends Outer1<E>{
public class Inner5 extends Inner1 {
}
}
Sie sind nur in der Lage
test = new Outer5<Outer5<?>.Inner1>();
hinzufügen, aber nicht
test = new Outer5<Outer5<?>.Inner5>(); // FAILS!
auf etwas, das Inner1
als Typargument definiert.
Es gibt jedoch eine recht einfache Lösung für dieses Problem. Wenn Sie das Objekt wie folgt definieren:
Outer1<? extends Outer1<?>.Inner1> test2;
sind Sie tatsächlich in der Lage, die folgenden Dinge zu tun:
test2 = new Outer1<Outer1<?>.Inner1>();
test2 = new Outer2<Outer2<?>.Inner1>();
test2 = new Outer3<Outer3<?>.Inner3>();
test2 = new Outer4();
test2 = new Outer5<Outer1<?>.Inner1>();
test2 = new Outer5<Outer5<?>.Inner1>();
test2 = new Outer5<Outer5<?>.Inner5>();
wie Sie jetzt explizit den Compiler gesagt, dass entweder die Inner1
Typ selbst oder einer ihrer Erweiterungen ist erlaubt.
-Code
Ich habe Ihren Code aktualisiert und ein paar neue Aufgaben hinzugefügt, um sicherzustellen, dass die tatsächlich vorgenommenen Änderungen produzieren keine Fehler oder Warnungen kompilieren mit Ausnahme der redundant type arguments in new expression
aufgrund explizit die Typargumente spezifiziert anstelle der Verwendung des Diamant-Operator <>
:
public class GenericInnerRecursion
{
// base class, consisting of outer and inner parts
public static class Outer1<E extends Outer1<?>.Inner1> {
public class Inner1 {
}
public void addElement(E e) {
System.out.println("Added " + e.toString());
}
}
// extending outer, but not inner
public static class Outer2<E extends Outer1<?>.Inner1> extends Outer1<E>{
}
// extending both outer and inner
public static class Outer3<E extends Outer3<?>.Inner3> extends Outer1<E>{
public class Inner3 extends Inner1 {
}
}
// extending both outer and inner and stopping extension
public static class Outer4 extends Outer1<Outer4.Inner4> {
public class Inner4 extends Outer1<Inner4>.Inner1 {
}
}
public static class Outer5<E extends Outer1<?>.Inner1> extends Outer1<E>{
public class Inner5 extends Inner1 {
}
}
// instantiating
public static void main(String[] args) {
Outer1<Outer1<?>.Inner1> a1;
a1 = new Outer1<Outer1<?>.Inner1>();
Outer1<?> a2;
a2 = new Outer1<>();
Outer1<Outer1<?>.Inner1> a3;
Outer1<? extends Outer1<?>.Inner1> a4;
a4 = new Outer1<Outer1<?>.Inner1>();
Outer2<Outer1<?>.Inner1> b1;
b1 = new Outer2<Outer1<?>.Inner1>();
// and so on
// assigning extension-classes to the parent-class
Outer1<Outer1<?>.Inner1> c1;
c1 = new Outer2<Outer2<?>.Inner1>();
// assigning inner-extension-classes to parent-class
Outer1<Outer3<?>.Inner3> c2;
c2 = new Outer3<Outer3<?>.Inner3>();
// assigning extension class without specified generics to parent class
Outer1<Outer4.Inner4> c3;
c3 = new Outer4();
Outer1<Outer1<?>.Inner1> test;
test = new Outer1<>();
test = new Outer2<>();
test = new Outer5<Outer5<?>.Inner1>();
Outer1<? extends Outer1<?>.Inner1> test2;
test2 = new Outer1<Outer1<?>.Inner1>();
test2 = new Outer2<Outer2<?>.Inner1>();
test2 = new Outer3<Outer3<?>.Inner3>();
// new Outer3<Outer3<?>.Inner1>(); not possible as generic type extends Outer3<?>.Inner3 and not Outer1<?>.Inner1!
test2 = new Outer4();
test2 = new Outer5<Outer1<?>.Inner1>();
test2 = new Outer5<Outer5<?>.Inner1>();
test2 = new Outer5<Outer5<?>.Inner5>();
}
}
Erweiterung wie 'Outer4' ist der einzige Weg, eine solche Art zu verwenden (da sonst die Parametrierung der Art unendlich rekursiv). Gibt es einen Grund, warum Sie eine so strikte Erklärung brauchen? 'E E erweitert Outer1 > .Inner1' wird viel weniger Kopfschmerzen. Wie werden Sie diese Klassen verwenden? – Radiodef