2015-07-10 6 views
11

Ich habe drei Klassen:Nested erstreckt sich in Generika

class ClassR {} 
class ClassA<T extends ClassR>{}  
class ClassB<E extends ClassA<T extends ClassR>> extends ClassA<T> { 
    void foo(T param) { 
    } 

    void bar(E param) { 
    } 
} 

Die dritte Klasse nicht kompilieren, wenn ich es ändern zu

class ClassB<E extends ClassA<T>, T extends ClassR> extends ClassA<T> { 
    void foo(T bar) { 
    } 

    void bar(E param) { 
    } 
} 

Gibt es eine Möglichkeit nur E-Parameter zu halten, ich übergeben müssen beim Erstellen von ClassB und T wird abgeleitet? Zum Beispiel wäre es zweckmäßig sein, zu verwenden:

new ClassB<ClassA<ClassR>>() 

statt:

new ClassB<ClassA<ClassR>, ClassR>() 
+0

Randbemerkung: es ist besser Runnable zu implementieren als Thema zu erweitern. – m0skit0

+0

geändert in ClassR, da es keinen Unterschied macht – Nutel

+1

Bitte posten Sie die Methode mit der Verwendung von E – Al1en313

Antwort

0

Nicht sicher, ob dies die Antwort ist, dass Sie wollen, aber sicher die einfachste Version lautet:

class ClassR { 
} 

class ClassA<T extends ClassR> { 
} 

class ClassB<T extends ClassR> extends ClassA<T> { 

    void foo(T bar) { 
    } 
} 

public void test() { 
    ClassB<ClassR> classB = new ClassB<>(); 
} 
+0

Mein Schlechter, ich benutze sowohl E als auch T innerhalb des ClassB, gibt es einen Weg, immer noch E zu haben? (aktualisiert die Frage) – Nutel

1

Dieser noch einfachere Ansatz könnte für Sie funktionieren:

class ClassR {} 
class ClassA<T extends ClassR>{}  

class ClassB<T extends ClassR> extends ClassA<T> { 
    void foo(T bar) { 
    } 

    void bar(ClassA<T> param) { 
    } 
} 

Und Nutzung umgeht dann jeder Verweis auf ClassA werden:

class SubR extends ClassR {} 

ClassB<SubR> obj = new ClassB<SubR>(); 
+0

Ich denke, das ist eine gute Antwort. Nach dem gezeigten Code wird 'E' nie von einer Methode in ClassB zurückgegeben. In ClassB (z. B. in der Methode 'bar') wissen Sie (der Compiler) jedoch nur, dass es sich um eine Klasse handelt, die als ClassA angesehen werden kann. Daher können Sie nur Methoden aus ClassA und T typsicher aufrufen. Daher ist der Typ-Parameter 'E' nicht erforderlich. Wenn es jedoch einen Code mit einer Referenz auf eine Instanz von ClassB gibt, die Methoden von 'E' aufruft, sind die Dinge wirklich anders. – Sebastian

0

Als Typen E erstreckt ClassA Sie sicher die ClassA Typparameter in ihrer Erklärung weglassen.
Korrekter ClassA Typ-Parameter wird im zweiten Parameter auf ClassB erzwungen.
Code unten zur Veranschaulichung Siehe:

class ClassB<E extends ClassA, T extends ClassR> extends ClassA<T> { 

    private ClassA ob; 

    public ClassB(E e, T t) { 
    super(t); 
    ob = e; 
    } 

} 

Nutzungs Beispiel:

class ClassR { 
    public ClassR() {}; 
} 

class ClassS extends ClassR { 
    private int x; 
    public ClassS(int x) { 
    super(); 
    this.x = x; 
    } 
} 

public static void test() { 
    ClassS data1 = new ClassS(1); 
    ClassB <ClassB, ClassS> first = new ClassB<>(null, data1); 
    ClassS data2 = new ClassS(2); 
    ClassB <ClassB, ClassS> second = new ClassB<>(first, data2); 
} 
+0

Mit dieser Lösung erhalten Sie ClassA als Rawtype und erben von ClassA . Wann immer Sie Informationen über den generischen Typ von ClassA in 'E extends ClassA' benötigen, sind Sie verloren. Wie oben erwähnt, denke ich, dass es einen Konstruktionsfehler gibt, der uns daran hindert, eine gute Implementierung zu liefern, da der gezeigte Code wie implizite Anforderungen riecht. – Sebastian

Verwandte Themen