2013-07-18 2 views
13

a Liste dann Warum kompiliert der Code (unten)? Sicher MyClass2 sollte eine List<Integer> zurückgeben?Warum kompiliert diese Klasse, obwohl sie ihre Schnittstelle nicht richtig implementiert?

public class Main { 
    public static void main(final String[] args) { 
    MyClass myClass = new MyClass(); 
    List list = myClass.getList(); 
    System.out.println(list); 
    System.out.println(list.get(0).getClass()); 

    MyClass2 myClass2 = new MyClass2(); 
    List list2 = myClass2.getList(); 
    System.out.println(list2); 
    System.out.println(list2.get(0).getClass()); 
    } 

    public interface Int1 { 
    public List getList(); 
    } 

    public interface Int2 extends Int1 { 
    @Override 
    public List<Integer> getList(); 
    } 

    public static class MyClass implements Int2 { 
    @Override 
    public List<Integer> getList() { 
     return Arrays.asList(1, 2, 3); 
    } 
    } 

    public static class MyClass2 implements Int2 { 
    @Override 
    public List getList() { 
     return Arrays.asList("One", "Two", "Three"); 
    } 
    } 
} 

ich bemerkt, wenn Sie versuchen, es zu machen, ein List<String> dann erhalten Sie einen Fehler „java: Main.MyClass2 nicht abstrakt ist und überschreibt nicht abstrakte Methode getList() in Main.Int2“. Ich verstehe nicht ganz, warum Sie das im obigen Beispiel nicht verstehen.

Hinweis: Die Lösung für das Problem in meinem Projekt ist, die Schnittstelle selbst generisch zu machen, d. H. Int1<X> (natürlich verwende ich bessere Namen als dies, es ist nur ein Beispiel).

+6

Sie sollten normalerweise Warnungen in Ihrem Compiler-Ausgang haben – fge

+0

Weil Java Generics saugen. – schlingel

Antwort

5

Die Antwort ist in JLS 7 5.5.1. Reference Type Casting:

einen Compiler-Referenztyp S (Quelle) und ein Compiler- Referenztyp T (Ziel) gegeben, ein Guss Umwandlung von S existiert auf T wenn Aufgrund der folgenden Regeln treten keine Kompilierungsfehler auf.

Wenn S ein Klasse-Typ ist:

If T is a class type, then either |S| <: |T|, or |T| <: |S|. Otherwise, a compile-time error occurs. 

Furthermore, if there exists a supertype X of T, and a supertype Y of S, such that both X and Y are provably distinct parameterized types 

(§4.5), und dass die Löschungen von X und Y gleich sind, eine Übersetzungszeit Fehler auftreten.

In Ihrem Fall List<Integer> und List<String> sind beweisbar verschiedene parametrisierte Typen und sie haben beide gleiche Löschungen: List.

7

Ich vermute, sollte der Compiler Sie werden geben für die Warnung Ungeprüfter Umwandlung, anstatt Kennzeichnung als Compilerfehler Lassen Sie uns verstehen, warum es Sie warnt:

Sie haben folgende zwei Methoden zur Umsetzung des Vertrages von Schnittstelle erfüllen Sie implementieren:

public List getList(); 
public List<Integer> getList(); 

Wenn nun in der Klasse, die Sie gerade Durchführung des ersten Verfahrens zur Verfügung stellen Es kann die Anfrage für die 2 nd Methode behandeln. Sie können eine List<Integer> mit dem Rückgabetyp List zurückgeben. Das ist, weil ein List<Integer> nichts anderes als ein List zur Laufzeit ist, aufgrund Typ löschen.

Aber, wenn Sie nur die 2 nd Methodenimplementierung geben, wird es den Vertrag der ersten Methode nicht erfüllen. Die erste Methode besagt, dass sie einen beliebigen Typ von List zurückgeben kann, da sie im Rückgabetyp den Raw-Typ verwendet hat. So kann es List<Integer>, List<Object>, List<String>, alles zurückgeben. Aber die 2 nd Methode kann nur List<Integer> zurückgeben.

Compiler führt diese Typüberprüfung zur Kompilierzeit durch und es gibt Ihnen eine Warnung, dass List unkontrollierte Konvertierung zu List<Integer> erfordert, weil die Konvertierung irgendwie zur Laufzeit aufgrund von Typ löschen erfolgreich sein wird.


Dies ist der Fall ähnlich wie unten:

List<String> listString = new ArrayList<String>(); 
List rawList = new ArrayList(); 

listString = rawList; // Warning: Unchecked conversion 
rawList = listString; 

Empfohlene Lesung:

+0

Ich verstehe nicht, wie wir haben "zwei Schnittstellen Vertrag zu erfüllen". Eine Schnittstelle überschreibt die andere, also ist es sicher 'Int2', die 'MyClass2' zu sättigen hat? Wie kann eine Anforderung für eine "List" eine für eine "List " behandeln? Ich weiß, dass sie nach dem Typ löschen die gleichen sind, aber sie sind nicht die gleichen, bevor sie kompiliert werden, weil in letzterem die Typen von dem, was Sie hinzufügen/löschen, usw. überprüft werden. –

+0

@PaulRichards.Ja, eigentlich implementieren Sie nur eine einzige Schnittstelle. Was erweitert die erste Schnittstelle. Sie können also sagen, dass Sie nur den Vertrag der einzelnen Schnittstelle erfüllen müssen. Das erbt Methode von einer anderen Schnittstelle. –

+0

Wie gesagt, eine Methode mit dem Rückgabetyp 'List' kann einen beliebigen Listentyp zurückgeben. Es kann also auch die Liste zurückgeben. Also, darum geht es bei der anderen Methode. Es sollte 'List ' zurückgeben, was mit 'List' gemacht wird. –

4

Die Signatur von public List<Integer> getList() ist die gleiche wie die Signatur von public List getList() nach Typ löschen. Für überschreibende Methoden benötigen Sie die überschreibende Methode als Untersignatur der überschriebenen Methode. Der Compiler hier wird entscheiden, dass die Unterklassenmethode die Schnittstelle 1 überschreibt, wenn sie nach dem Typ löschen identisch sind und wir niemals einen Konflikt haben können.

4

Dieses wahrsten Sinne des Wortes, hat keinen Effekt, weil der Typ Löschung:

public interface Int1 { 
    public List getList(); 
} 

public interface Int2 extends Int1 { 
    @Override 
    public List<Integer> getList(); 
} 

Zur Laufzeit jeder List<X> wird List. Deshalb hast du hier nichts @Override. Der Laufzeitprototyp .getList() ist List getList(). Die Tatsache, dass Sie Ihre List in Int2 parametrieren, wird komplett ignoriert.

Der Compiler warnt Sie dazu:

java: Note: Main.java uses unchecked or unsafe operations. 
java: Note: Recompile with -Xlint:unchecked for details. 
0

So ist es wie mit ihr verbundenen sieht Löschung und seine die Art der Sache zu geben, die eine Warnung eher als ein Compiler-Fehler erzeugt. Ich denke, es ist wie bei den anderen unkontrollierten Konvertierungsszenarien, die ich zuvor gesehen habe. Danke für die gut recherchierten Antworten.

Verwandte Themen