2013-02-14 10 views
7

Warum fallen Sammlungen, die nicht mit der Vorlagenklasse zusammenhängen, ihren Typ? Hier ein Beispiel: (Sorry, es wird nicht kompiliert, da der Fehler über Ich bin verwirrt.)Generische Verschraubungen nicht zusammenhängender Sammlungen

package test; 

import java.util.ArrayList; 
import java.util.List; 

public class TemplateTest { 

    public static class A { } 

    public static class B<T extends Comparable> { 
     List<A> aList = new ArrayList<A>(); 

     public List<A> getAList() { 
      return aList; 
     } 

     public int compare(T t, T t1) { 
      return t.compareTo(t1); 
     } 
    } 

    public static void main(String[] args) { 
     B b = new B(); 
     for (A a : b.getAList()) { //THIS DOES NOT WORK 

     } 
     List<A> aList = b.getAList(); //THIS WORKS 
     for (A a : aList) { 

     } 
    } 
} 

Dieser Code wirft einen Fehler bei der Zusammenstellung:

test/TemplateTest.java:24: incompatible types 
    found : java.lang.Object 
    required: test.TemplateTest.A 
     for (A a : b.getAList()) { 

Wenn ich die Vorlage angeben von B wie B<String>, oder wenn ich die Vorlage komplett aus B entferne, dann ist alles in Ordnung.

Was ist los?

EDIT: Leute darauf hingewiesen, gibt es keine Notwendigkeit ich generic B so zugesetzt, um war

+1

Traurig über den Unsinn vor ... Das scheint mit einem Fehler verbunden sein. Kudos! –

+1

Nicht strikt auf Ihre Frage bezogen, aber * nicht * das Angeben des Typparameters in Java wird im Allgemeinen als Programmierfehler betrachtet. Die Verwendung des Rohtyps kompiliert nur als Zugeständnis an Rückwärtskompatibilität. – Affe

+0

Ich rufe Compiler-Fehler auch. Es scheint, als ob der Typ des Ausdrucks auf der rechten Seite, der in einer erweiterten for-Schleife verwendet wird, auf eine spezielle Art und Weise bestimmt wird (nicht überraschend, da er Spezialfälle benötigt), und das bricht, wenn ein roher Typ beteiligt ist. (Ich sehe einen rohen Typ irgendwo, er nimmt an, dass der ganze Ausdruck Typen gelöscht hat.) – millimoose

Antwort

8

Ja, ist es bekannt, Verhalten, dass wenn Sie ein Rohgewebe, dann Alle Typparameter der Klasse gehen verloren, nicht nur der Parameter auf Typpegel, den Sie nicht deklarieren konnten.

Die Frage ist zum Teil hier:

Wenn ich die Vorlage von B wie B<String> angeben, oder wenn ich die Vorlage von B vollständig entfernen, dann ist alles in Ordnung.

Das ist keine Option, Sie müssen nicht auswählen, ob Sie den Typparameter angeben möchten oder nicht. Der einzige Grund, warum es überhaupt ohne Parameter kompiliert wird, ist Rückwärtskompatibilität. Das Schreiben eines neuen Codes mit fehlenden Typparametern ist ein Programmierfehler.

List<A> list = b.getList() nicht erfolgreich den Typ zu interpretieren, es ist nur effektiv in einer willkürlichen Besetzung haften und Ihnen zu vertrauen, dass die Zuordnung korrekt ist. Wenn Sie sich die Compiler-Warnungen ansehen, wird in der Tat eine Warnung für eine unsichere Konvertierung erzeugt.

aktualisiert diese Warnung auf einen Fehler, da die eingefügte Umwandlung in Compiler-generiertem Code enthalten ist. Daher verweigert sie die automatische Generierung von unsicheren Code und gibt keine Warnung aus.

aus der Java-Sprachspezifikation:

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

Unterm Strich ist wirklich, dass der einzige bedeutende Sache Java Generics Anteil mit C++ Vorlagen die < ist> Syntax :)

Weitere Details: What is a raw type and why shouldn't we use it?

+0

Aber Sun akzeptiert den Fehler, den ich in http://stackoverflow.com/a/14882182/688653 erwähnt habe. Ist das also ein Fehler oder das richtige Verhalten? –

+0

Okay, aber das erklärt nicht wirklich, warum der Ausdruckstyp * außerhalb * des Kontexts einer erweiterten for-Schleife korrekt bestimmt wird. – millimoose

+0

@millimoose Ich glaube nicht, dass es außerhalb bestimmt ist, aber ich bekomme eine Warnung statt eines Fehlers. ZB 'List list = notDeclared.getAList();' gibt mir eine 'ungeprüfte Konvertierung' Warnung. – sharakan

1

Zuerst nach B, in Java, es ist Generics, nicht Vorlagen wie es in C++ ist.

Sie deklarieren einen generischen Typparameter T in Ihrer Klasse B, aber Sie verwenden ihn nicht. Sie sollten T anstelle von A in Ihrer B Klasse verwenden.

public static class B<T> { 
    List<T> aList = new ArrayList<T>(); 

    public List<T> getAList() { 
     return aList; 
    } 
} 

Dann sollten Sie einen Typ-Parameter verwenden, wenn Sie Ihre Instanz der Klasse B erklären.

B<A> b = new B<A>(); 

Aber wenn Sie wissen, dass Ihre aList variable Objekte vom Typ immer getAList schlägt A als Methodennamen halten wird, dann gäbe es keinen Grund, Klasse B Generika zu machen.

+0

Ich kann T woanders verwenden, aber selbst wenn ich es tue, vermassele ich A, wenn ich T nicht spezifiziere. Warum ist das? – naugler

+0

Die Angabe eines generischen Typparameters für Klasse B bedeutet, dass seine "getAList" -Methode eine Liste eines bestimmten Typs "T" zurückgibt, aber es ist uns egal, um welchen Typ es sich handelt. Der Typ von "T" wird nicht angegeben, bis eine Instanz erstellt wurde. Wenn Sie Ihre Instanz "b" vom Typ "B" erstellen, geben Sie den Typparameter "A" an, sodass Sie beim Aufruf von "getAList" eine Liste zurück erhalten. – rgettman

+0

Nein, ich möchte, dass die Liste vom Typ A ist. Der Typ T wird an anderer Stelle verwendet. Warum löscht meine Liste von A-Objekten den Typ? (Ich habe zu meinem Beispiel hinzugefügt, um eine mögliche Verwendung von T zu zeigen, tut mir leid, es ist grob) – naugler

1

Dies ist zu diesem Fehler wirklich ähnlich:

6760983 : Unused type parameter triggering error in unrelated method

die hier berichtet wird:

Unused Generic causing problem

+0

Aber der OP-Code ist keine Unterklasse, also gibt es keine Überschneidungen oder Namenskonflikte, wie der Fehler vermuten lässt. – splungebob

+0

Wahr, aber in diesem Fehler verwirrte der zusätzliche Typparameter den Compiler, so dass die Typprüfung an zwei (scheinbar) übereinstimmenden Typen fehlschlug, genau wie hier. Vielleicht sind sie verwandt? Ein anderer Gedanke: Vielleicht kann hier eine andere Implementierung von Java helfen? –

+0

@ZiyaoWei Sie könnten den Eclipse-Compiler anstelle der Sun-Version ausprobieren. – millimoose

Verwandte Themen