2013-07-19 4 views
12

Wenn ich eine Klasse:Warum löscht eine generische Java-RAW-Klasse alle generischen Objekte, wenn keine Typparameter angegeben sind?

public class GenericClass<TBlah extends Number> { 
    public List<String> getList() { 
     return null; 
    } 
} 

Wenn ich diese Methode von einer anderen Klasse zu verwenden versuchen:

public class OtherClass { 
    public void test() { 
     GenericClass a = null; 
     for (String s : a.getList()) { 

     } 
    } 
} 

Warum ein List<Object> nicht a.getList() zurück, bis ich die Zeile oberhalb der for-Schleife zu ändern:

GenericClass<Number> a = null; 

An welchem ​​Punkt a.getList() gibt ein List<String> wie sollte es tun?

Edit: Ich verstehe nicht, warum der Vertrag, der von getList() angegeben wird, von wie auch immer betroffen sein sollte, wie ich meine Variable 'a' deklariere. getList() gibt immer eine List<String> zurück, es ist egal, was TBlah ist.

+1

Uhm, warum initialisiere ich ihn auf "null"? – fge

+0

@fge Einfachheit. Es ist irrelevant für das Problem, denke ich. – Xenoprimate

+7

Denn das ist die Entscheidung der Autoren der JLS. AFAIK, die Argumentation ist, dass wenn Sie rohe Typen verwenden, Sie sich nicht um generische Typen kümmern. Die Lösung besteht darin, die Verwendung von Rohtypen zu vermeiden. –

Antwort

8

Weil so Generika funktionieren. Vergessen Sie nicht, dass vor Generika, als Sie eine List deklarierten, war es eine Liste von Object. Sie sollten Object setzen/erhalten und Sie wurden gezwungen, Ihr Objekt mit dem richtigen Typ zu erfassen. Eigentlich ist es immer noch ist eine Liste von Object in Laufzeit.

Generics ist eine Möglichkeit für den Compiler, Ihnen die Sicherheit zur Kompilierzeit zu geben, vorausgesetzt, Sie haben keine Warnungen. Zur Laufzeit gibt es keine List<String>. Es gibt nur List. Der Compiler stellt den automatischen Cast für Sie bereit, sodass Sie in Ihrem Code String s = list.get(i) ohne Casting schreiben können.

Wenn Sie GenericClass a deklarieren, deklarieren Sie einen unformatierten Typ (Sie sollten eine Warnung dazu erhalten), daher hat der Compiler keine Möglichkeit zu wissen, welchen Typ die a.getList() zurückgeben soll. So verwendet es Object. Wenn Sie nun GenericClass<Number> a = null; deklarieren, weiß der Compiler, welcher Typ für die a.getList() erwartet wird und verwendet den gewünschten.

Edit: Es soll klargestellt werden, dass die Compiler wissen können, was nur erwarten, wenn Sie den Vertrag der Unterschrift respektieren (das heißt, wie der Fall mit GenericClass<Number> ist). Wenn Sie den Vertrag nicht einhalten (d. H. Sie verwenden einen Rohtyp, der nicht extends Number lautet), gilt der Vertrag nicht mehr. Der Compiler verhält sich so, als ob keine Typinformation vorhanden wäre. Vergessen Sie nicht, dass der Compiler auch Abwärtskompatibilität mit dem Code aufrechterhalten muss, der im Zeitalter der Prägenerika erstellt wurde

+0

Das ist irgendwie vernünftig. Aber warum weiß der Compiler nicht, was a.getList() zurückgeben soll? Es ist genau dort in der Methodensignatur. Und das ändert sich nicht, egal, was ich TBlah zu sein habe ... Warum ist es dann wichtig, dass ich den rohen Typ verwende? – Xenoprimate

+0

Das ist nicht korrekt. Es ist nicht in der Signatur. Die Signatur sagt ein "Blah, das Nummer ausdehnt". Sie haben einen rohen Typ (dh ein einfaches 'Objekt') verwendet, so dass die Signatur nicht mehr zutrifft, weil' Objekt' nicht 'Zahl' erweitert. –

+1

Aber der Rückgabetyp der Liste in getList() ist unabhängig von der Wahl von TBlah sein. Also warum ist es wichtig? – Xenoprimate

-2

Sie benötigen einen Platzhalter/Verweis auf die Liste Bezug zu nehmen und Referenz von derselben type.like sein muss,

Liste < String> x = a.getList();

Verwandte Themen