2014-01-21 5 views
5

Sprich: Ich habe eine Methode:Warum ist die Typrückschlussart von Java so schwach?

public static <T> Collection<T> addToCollection(T element, Collection<T> collection) { 
    collection.add(element); 
    return collection; 
} 

Und dann, wenn Sie diesen Code zu kompilieren versuchen:

Integer i = 42; 
Collection<Integer> result = addToCollection(i, Collections.emptyList()); 

ich Type mismatch: cannot convert from Collection<Object> to Collection<Integer> einen Fehler. Könnte jemand erklären, warum das Typsystem nicht folgern kann, dass Collections.emptyList() vom Typ Collection<Integer> sein sollte?

Das obige Beispiel ist offensichtlich ziemlich künstlich, aber ich stolpere ständig über diese Einschränkung und es ist wirklich nervig. Nachdem ich gelesen habe Effektive Java Ich habe herausgefunden, dass Sie einfach tun Collections.<Integer>emptyList() (muss sagen, das war eine Offenbarung für mich zu der Zeit) und alles kompilieren reibungslos, aber wenn Sie einige komplizierte Art haben, dann ist es wirklich ein Ärgernis.

Ich frage mich nur, ob dies eine Art von Bug ist, oder gibt es gültige Gründe dafür, dass es so funktioniert?

+9

Können Sie den Titel freundlicherweise umformulieren? – Kobi

+3

Sprechen Sie über den Topf, der den Kessel schwarz nennt. Collections.emptyList() gibt eine nicht änderbare Liste zurück, so dass der Code sowieso nicht funktioniert. – Kayaman

+3

@Kayaman neben dem Punkt, wie OP selbst angezeigt. Die Frage bezieht sich auf die Prinzipien der Schlussfolgerung, Laufzeit spielt nicht eine Rolle. –

Antwort

11

Das Typ-Inferenz-System wurde in Java 8 mit der Einführung von target typing verbessert, um Streams und Lambdas mehr Ausdruck zu verleihen. Als Konsequenz kompiliert Ihr Code mit Java 8.

Mehr darüber in der updated tutorial, mit einem sehr ähnlichen Beispiel ganz unten auf der Seite.

+0

TIL! Das ist großartig - ich habe selbst in diesen Situationen hässliche Wörter bei Javac gemurmelt. Ich muss das morgen ausprobieren (habe jdk 8 auf dieser Maschine). Werde ich enttäuscht sein, wenn ich auch diese bessere Schlussfolgerung erwarte, wenn ich mit Seestern zusammenarbeite? 'Liste foo = myBool? someList: Collections.emptyList() ' – yshavit

+1

@yshavit Das kompiliert auch. – assylias

+1

Vor vielen Jahren, zu der Zeit des epischen BGGA/CICE/FCM-Kampfes, las ich [irgendwo] (https://weblogs.java.net/blog/carcassi/archive/2010/04/09/zwei-probleme- generics-java-0), dass "Java sich darauf konzentrieren sollte, seine Generics zu fixieren, anstatt eine weitere Ebene der Komplexität einzubringen".Es stellte sich heraus, dass sie das erste als Dienst für das letztere taten. –

0

Collections.emptyList() gibt eine List<Object> zurück, die durch Ihre addToCollection() Methode weitergegeben wird. Und da Objekt nicht Ganzzahl ist, schlägt dies fehl.

+0

Das ist nicht wahr. Das ist eine generische Methode. –

+0

' öffentliche statische Liste emptyList()' --- eingeführt als Methode Wrapper um die Konstante 'EMPTY_LIST' nur aus diesem einen Grund. –

+0

Es ist eine generische Methode, aber es gibt zwei Möglichkeiten, den generischen Typ zu binden: entweder basierend auf den Argumenten oder basierend auf dem Rückgabetyp. Hier erfolgt die Bindung offensichtlich basierend auf dem zweiten Argument, das Sie übergeben. – rec

0

Was schadet dabei?

Integer i = 42; 
List<Integer> emptyList = Collections.emptyList(); 
Collection<Integer> result = addToCollection(i, emptyList); 

In Java 8 wird darauf geachtet werden.