2016-07-05 14 views
8

Ich bin auf etwas gestoßen, das ich in Java seltsam finde und ich konnte nicht viele Informationen darüber finden. Betrachten Sie den folgenden Code ein:Generika und abstrakte Methoden

public class TestClass { 

    private static abstract class AbstractClass { 
     abstract List<? extends Object> getList(); 
     abstract Map<Long, List<? extends Object>> getMap(); 
    } 

    private static final class ConcreteClass extends AbstractClass { 
     @Override 
     List<String> getList() { 
      return null; 
     } 

     @Override 
     Map<Long, List<String>> getMap() { 
      return null; 
     } 
    } 
} 

Der Compiler zeigt einen Fehler auf der getMap() Methode:

getMap() in ConcreteClass cannot override getMap() in AbstractClass 
    return type Map<Long, List<String>> is not compatible with Map<Long, List<? extends Object>> 

Aber den gleichen Fehler ist für die getList() Methode nicht vorhanden ist, aber ich würde erwarten, dass entweder beide arbeiten oder beide versagen. In beiden Fällen ist die übergeordnete Methode List<String> anstelle von List<? extends Object> delcaring. Kann jemand das erklären?

Antwort

10

Es ist, weil es eine implizite Konvertierung von List<String> zu List<? extends Object> existiert, aber nicht Map<Long, List<String>>-Map<Long, List<? extends Object>>.

Alle generischen Typen sind invariant, es sei denn, Sie verwenden Wildcard-Typen. Da in den generischen Argumenten des Typs "äußere" Map-Typen kein Platzhalter vorhanden ist, kann kein generischer Typ erfasst werden, der nicht genau übereinstimmt.

Wenn Ihr Kartentyp Map<Long, ? extends List<? extends Object>> wäre, dann würde es so funktionieren, wie Sie es erwarten. Der andere Teil, wenn die Antwort ist, dass Unterklassen eine Supertype-Methode mit einem anderen Rückgabetyp überschreiben oder implementieren können, aber nur, wenn der Rückgabetyp der Methode des Untertyps implizit in den Rückgabetyp der Supertypemethode konvertiert werden kann. (In Java 1.4 und darunter würde sogar das nicht funktionieren: Es wäre ein Kompilierzeitfehler, wenn die Typen nicht genau übereinstimmen würden.)

+0

Große Antwort, danke! (Ich werde akzeptieren, nachdem das Zeitlimit abgelaufen ist) – lucasvw

+3

der gute Punkt, ich möchte hinzufügen? extends Object 'kann durch'? 'ohne irgendeinen Effekt ersetzt werden – Andrew

+2

@Andrew: Sicher, aber das gleiche Prinzip gilt für jede Untergrenze auf dem Platzhalter, nicht nur für' Object'. –

Verwandte Themen