2016-04-07 16 views
0

Betrachten Sie das folgende Stück Code:Warum Superklassen generischer Typ nicht gelöscht/gegossene

class A<T>{ 
T t; 

public T getValue(){ 
    return t; 
} 

class B<S extends Number> extends A<String>{ 

//some code here.. 
} 

B b = new B<Integer>(); 
String name = b.getValue() // This throws compilation error 

während der folgenden Werke:

B<Integer> b = new B<Integer>(); 
String name = b.getValue() // This works...! 

Also meine Fragen sind:

  1. Muss ich alle beteiligten Generika angeben? (Obwohl der generische Typ der Klasse A in Klasse B deklariert wurde.)

  2. Oder fehlt mir im Grunde etwas?

+2

Sie den entscheidenden Teil weggelassen haben, die die Deklaration von 'B.getValue ist()'. –

+0

Between, warum sollte ich die Methode in B überschreiben, wenn ich kein Verhalten von getValue() ändern möchte? Außerdem wurde der A-Typ in B als Long deklariert, um ihn zu löschen. –

+0

@JimGarrison aber die Deklaration für 'getValue' ist in der Klasse' A' – SomeJavaGuy

Antwort

3

Siehe JLS 4.8 Raw Types:

eine rohe Art definiert werden, [...] der Referenztyp, indem man den Namen einer generischen Typdeklaration ohne eine begleitende Typ Argumentliste gebildet wird.

Die Superklassen (bzw. Superinterfaces) eines Raw-Typs sind die Radierungen der Superklassen (Superinterfaces) eines seiner parametrisierten Aufrufe.

Mit anderen Worten, wenn Sie B ohne <> verwenden, wird es eine rohe Art, im Grunde alle Generika, den ganzen Weg bis alle Basisklassen und Schnittstellen zu löschen, also ist, so als würde A und B weren‘ t generic:

class A { 
    Object t; 
    public Object getValue() { 
     return t; 
    } 
} 

class B extends A { 
    //some code here.. 
} 

, weshalb String name = b.getValue() versagt, weil getValue() nun eine Object zurück.


Beachten Sie die folgenden Kommentar im JLS:

Die Verwendung von rohen Typen wird nur als Zugeständnis an die Kompatibilität von Legacy-Code erlaubt. Die Verwendung von Rohtypen in Code geschrieben nach der Einführung von Generika in die Java-Programmiersprache wird dringend empfohlen. Es ist möglich, dass zukünftige Versionen der Java-Programmiersprache die Verwendung von Rohtypen verbieten.

Kurz gesagt, NICHT. Korrigieren Sie Ihren Code, um keine unformatierten Typen zu verwenden.

Sie können jedoch verkürzen die rechte Seite wie folgt:

B<Integer> b = new B<>(); 
-1

Der generische Wert der Klasse B hat einfach keine Verbindung mit dem einem aus der Klasse A.

Verfahren getValue T() einem A (Long) lange getValue() sein, jede Generik abgesehen auf der Wickelklasse.

Wenn Sie ein Integer getValue() wollen, dann gehen Sie einfach für

class B extends A<Integer> {} 

EDIT: Sie Ihre Frage ändern, können die Antwort ändern :)

B als B betrachtet wird (S Nummer erstreckt, T) (weil es A erweitert). Wenn Sie eine Variable als Raw-Typ B speichern, ist dies implizit B (Object, Object), auch wenn sie ordnungsgemäß deklariert ist.

Make Test mit einer Liste

List l = new ArrayList<String>(); 
String s = l.get(0); 

Sie werden mit dem gleichen Problem beenden.

+0

Ich habe die Frage bearbeitet, da die frühere Verwirrung zwischen Number und Long verursacht, es ist jetzt besser zu verstehen, was ich meine. –

+0

Ich denke, dass OP lieber wissen will, obwohl das generische 'S' nicht mit der Klasse' A' verwandt ist, und während 'getValue' aufgrund der Deklaration der Klasse' B' bereits ein 'Long' zurückgeben sollte, warum er muss das generische "S" bereitstellen, während die Variable definiert wird, damit "B" eine "Long" für "A # getValue" zurückgibt, während sie ohne sie ein "Objekt" zurückgibt. – SomeJavaGuy