2015-10-16 12 views
7

Hier ist der Code:Generics Typ Löschung in Java

public class Main { 
    public static void main(String[] args) { 
     Gen<Integer> g = new Gen<Integer>(5); 

     System.out.println(g.getClass()); 
     System.out.println(g.ob.getClass()); 
    } 
} 

class Gen<T> { 
    T ob; 

    public Gen(T x) { 
     ob = x; 
    } 
} 

Und hier ist der Ausgang

class Gen    // This I understand 
class java.lang.Integer // But if type erasure is happening, shouldn't this be java.lang.Object? 

ich es, dass Typ-Parameter T wird zur Laufzeit gelöscht, aber warum dann ist der Typ-Parameter ob Überleben zur Laufzeit?

+3

Sie müssen anfangen, zwischen Variablen, Referenzen und Objekten zu unterscheiden, –

+2

Wenn 'Car c = new Mercedes();' Was denken Sie, sollte Ergebnis von 'c.getClass()' sein und warum? – Pshemo

+0

danke an alle für die antwort ich bekomme es jetzt – Ramanlfc

Antwort

0

Da meine erste Exposition gegenüber Generika mit C# war, dauerte es einige Zeit, um herauszufinden, welche Art von Löschung in Java ist.

Aber nach besserem Verständnis von Java-Generika erkannte ich, dass ich in meiner Frage 2 separate Themen mische: Generics and Reflection.

Die wichtigste Frage war, warum hier den zweiten Anruf

tat
System.out.println(g.getClass()); 
System.out.println(g.ob.getClass()); 

zurück java.lang.Integer statt java.lang.Object.

bei der Dokumentation der Suche nach getClass(), wird die Antwort auf der Hand

Gibt die Laufzeit Klasse dieses Objekts.

Also, getClass() gibt nicht den Referenztyp zurück, sondern das tatsächliche Objekt, auf das sich die Referenz bezieht.

Für Ex:

Object o = "abc"; 
System.out.println(o.getClass()); 

Der Ausgang würde nicht der Typ, der java.lang.Object Referenz sein, sondern der tatsächlichen Typ des Objekts java.lang.String.

2

Type erasure geschieht. Generics sind ein Kompilierzeit-Typprüfsystem. Zur Laufzeit erhalten Sie immer noch die Klasse (es handelt sich um Informationen zum Laufzeittyp). Die verlinkte Type-Löschungsdokumentation sagt (teilweise)

Generics wurden in die Java-Sprache eingeführt, um strengere Typprüfungen zur Kompilierungszeit bereitzustellen und generische Programmierung zu unterstützen. Um Generics zu implementieren, wendet der Java-Compiler das Typlöschen an:

Ersetzen Sie alle Typparameter in generischen Typen durch ihre Grenzen oder Object, wenn die Typparameter unbeschränkt sind. Der erzeugte Bytecode enthält daher nur gewöhnliche Klassen, Schnittstellen und Methoden.

Ihre Instanz hat einen Typ, es ist Object. Aber eine Object Referenz kann auf jede Unterklasse (also jede Klasse) in Java verweisen. Sie erhalten den Typ, auf den es sich bezieht.

+0

Dies beantwortet nicht die Frage des OP, warum der Laufzeittyp des enthaltenen Objekts nicht "gelöscht" wird. – Random832

+0

Aber es ist (am Bytecode), er ist verwirrt rtti mit Kompilierzeit Informationen. –

4

Nein!

Bedenken Sie:

Object x = new Integer(1); 
System.out.println(x.toString()); 

Sie 1 bekommen.

Aber sollte ich nicht Object.toString() bekommen?

No. Während x eine Referenz vom Typ Object, der tatsächliche referent ist ein Integer, also während der Laufzeit, die Integer Umsetzung toString genannt wird.

Es ist das gleiche für getClass.

2

Unabhängig davon, welchen Typ die Variable hat, hängt der Rückgabewert getClass() von der Variablen ab. Also, da Sie im Grunde eine Variable Object ob haben, die eine Integer enthält (Ihre int wurde zu der Zeit konvertiert, als Sie es als den Parameter dieses Konstruktors zur Verfügung stellten), ist die Ausgabe ob.getClass()class java.lang.Integer.

Auch über Ihre Frage, warum getClass() erinnert sich an den Typ Argument: es tut nicht. Alles was es tut, ist die Klasse des Inhalts zu bestimmen. Zum Beispiel:

class Foo { 
    public Foo() {} 
} 

class Bar extends Foo { 
    public Bar() {} 
} 

class Baz<T> { 
    public T object; 

    public Baz(T object) { this.object = object; } 
} 

Wenn Sie jetzt die folgenden Ausschnitt laufen ...

public static void main(String... args) { 
    Baz<Foo> obj = new Baz(new Bar()); 
    System.out.println(obj.object.getClass()); 
} 

Sie werden feststellen, dass die Ausgabe nicht class Foo, es class Bar ist.

2

Da, wenn kompiliert, Klasse Gen hat ein Objekt ob; Die Generika verschwinden aus dem Endprodukt. Die eckigen Klammern spielen nur eine Rolle während der Kompilierzeit während der statischen Typprüfung. Es ist etwas, das der Compiler für Sie tun kann, um Ihnen eine bessere Sicherheit zu geben und Ihnen zu versichern, dass Sie Sammlungen und andere parametrisierte Typen korrekt verwenden.

Das eigentliche Objekt, das zur Laufzeit der Ob zugewiesen wurde, ist eine Instanz der Integer-Klasse, und ob.getClass() dient dem Zweck, die tatsächliche Klasse des Objekts zu finden, auf das der Zeiger verweist -> daher wird java angezeigt. lang.Integer gedruckt.

Denken Sie daran, was herauskommt, ist effektiv Klasse Gen {Objekt ob; ...}

+0

Dies erklärt nicht, warum 'getClass()' 'Integer' zurückgibt. –

+0

Das tatsächliche Objekt, das zur Laufzeit dem Objekt zugewiesen wurde, ist eine Instanz der Integer-Klasse. Und so würdest du es herausfinden ... –

+0

Das sollte dann in der Antwort sein –