2014-04-22 8 views
5

Wenn Sie eine Instanz einer generischen Klasse als Ausgangstyp in Java deklariert, wird der Compiler eine parametrisierte Art von Object für alle Teilnehmer, Methoden übernehmen? Gilt dies sogar für solche Verfahren, die eine Form (z. B. Collection) eines konkret parametrisierten Typs zurückgeben?Java - Verhalten der Klassenmitglieder von generischer Klasse

erklärte ich fälschlicherweise eine Instanz einer generischen Klasse ohne parametrisierte Typ, der zu sehr interessanten nachgelagerten Effekte führten. Ich habe ein vereinfachtes Beispiel für ein Szenario angegeben, das einen Kompilierungsfehler "inkompatibler Typen" verursachte. Meine grundsätzliche Frage: Warum produziert javac einen 'inkompatible types' Fehler und beschwert sich über die unten angegebene Zeile?

import java.util.*; 

public class Main { 
    public static void main(String[] args) { 
     final Test<String> t1 = new Test<String>(); 
     final Test t2 = new Test<String>(); 

     for (final Integer i : t1.getInts()) { 
      System.out.println(i); 
     } 
     for (final Integer i : t2.getInts()) { //<-- compile-time error 
      System.out.println(i); 
     } 
    } 

    public static class Test<T> { 
     public Test() { 
     } 

     public Set<Integer> getInts() { 
      final Set<Integer> outSet = new HashSet<Integer>(); 
      outSet.add(new Integer(1)); 
      outSet.add(new Integer(2)); 
      outSet.add(new Integer(3)); 
      return outSet; 
     } 
    } 
} 

Eine interessante Anmerkung ist, dass, wenn t2 mit einem Platzhalter-Typ deklariert wird (Test<?> t2…) der Code kompiliert und läuft wie erwartet.

Die Verwendung der for-Schleife aufruft next() jeder auf der Iterator auf dem Satz von getInts() zurückgegeben (die einen generischen Typ kehrt aus dem gewonnenen Iterable iteriert wird). The documentation here erwähnt, dass, wenn das Iterable rohe ist, Object als Rückgabetyp verwendet wird. Warum scheint der Compiler auch den Rückgabetyp von Test.getInts()Set<Integer>-Set<Object> zu ändern?

Antwort

5

Weil Sie ein rohes Test verwendet, werden alle Generika in der Test Klasse effektiv typ gelöscht, auch in keinem Zusammenhang Generika wie Set<Integer> Rückkehr, so dass die Set<Integer> von getInts zurückgegeben wird nur ein rohes Set. Das erklärt, warum Sie inkompatible Typen erhalten, weil eine rohe SetObject s zurückgibt, nicht Integer s.

Section 4.8 of the JLS deckt raw Arten:

Der Typ einer Konstruktor (§8.8), Instanzmethode (§8.4, §9.4) oder nicht-statisches Feld (§8.3) M eines rohen Typs C dass nicht von seinen Oberklassen oder Superschnitt geerbt ist der rohe Typ, der den Löschungs seiner Art in der generischen Deklaration entspricht C. entsprechenden

und

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

(Hervorhebung von mir)

Der Grund für dieses Verhalten für die Abwärtskompatibilität mit bereits Generika Java-Code, da die Pre-Generika-Versionen von integrierten Java-Klassen sind die gleichen Dinge wie die rohe Art Versionen der generierten integrierten Klassen. Das heißt, eine Prä-Generika Set ist die gleiche Sache wie eine rohe Set (Generika entfernt).

0

Ja, wenn eine Variable als Ausgangstyp deklariert (oder wenn der Ausdruck eine rohe Art Referenz löst), alle Interaktionen mit dieser Referenz handeln, als ob alle Generika wurden gelöscht. Dies umfasst generische Parameterlistentypen und Rückgabetypen.

Verwandte Themen