2009-08-06 20 views
8
public void wahey(List<Object> list) {} 

wahey(new LinkedList<Number>()); 

Der Aufruf der Methode wird nicht überprüft. Ich kann nicht einmal die Parameter wirft wie folgt:Warum ist die Liste <Number> kein Untertyp der Liste <Object>?

wahey((List<Object>) new LinkedList<Number>()); 

Aus meiner Forschung hat ich gesammelt, dass der Grund für die nicht erlaubt ist die Typsicherheit. Wenn wir durften die oben genannten tun, dann könnten wir folgende Voraussetzungen erfüllt sein:

List<Double> ld; 
wahey(ld); 

innerhalb der Methode Wahey, konnten wir einige Strings in die Eingabeliste hinzuzufügen (wie die Parameter einen List<Object> Referenzhält). Nach dem Aufruf der Methode verweist ld jetzt auf eine Liste mit dem Typ List<Double>, aber die eigentliche Liste enthält einige String-Objekte!

Dies scheint anders als die normale Art und Weise Java ohne Generika funktioniert. Zum Beispiel:

Object o; 
Double d; 
String s; 

o = s; 
d = (Double) o; 

Was wir hier tun, ist im Wesentlichen der gleiche, außer diese Kompilierung-Kontrollen passieren und nur zur Laufzeit fehlschlagen. Die Version mit Listen wird nicht kompiliert.

Dies führt zu der Annahme, dass dies eine rein konstruktive Entscheidung in Bezug auf die Typenzulassung von Generika ist. Ich hatte gehofft, einige Kommentare zu dieser Entscheidung zu bekommen?

+1

verwandt (kein exaktes Duplikat, obwohl die richtige Antwort im Grunde die gleiche ist): http: // stackoverflow.com/questions/251298/why-is-someclass-super-t-nicht-äquivalent-zu-someclasst-in-java-generischen-types – Kip

+3

Der Begriff der Kunst ist ** Kovarianz ** - ich erwähne dies, weil es macht es ist einfacher für Sie, es nachzuschlagen, einschließlich Stack Overflow (wenn Sie sehen möchten, was ich dazu zu sagen hatte - im Kontext von C#, aber es gilt auch für Java - suchen Sie nach [covariance user: 95810] zum Beispiel). –

+0

Ein Double Cast wie 'wahey ((Liste )) (Liste ) neue ArrayList ()) wird kompilieren, obwohl dies nicht empfohlen wird. – Robin479

Antwort

9

Was Sie im "ohne Generika" -Beispiel tun, ist eine Besetzung, die deutlich macht, dass Sie etwas Art-unsicher machen. Das Äquivalent mit Generika wäre:

Object o; 
List<Double> d; 
String s; 

o = s; 
d.add((Double) o); 

, die die gleiche Art und Weise verhält (compiliert, aber nicht zur Laufzeit). Der Grund dafür, das gewünschte Verhalten nicht zuzulassen, liegt darin, dass implizite Typ-unsichere Aktionen erlaubt werden, die im Code viel schwieriger zu bemerken sind. Zum Beispiel:

public void Foo(List<Object> list, Object obj) { 
    list.add(obj); 
} 

Das sieht völlig in Ordnung und typsicher, bis Sie es so nennen:

List<Double> list_d; 
String s; 

Foo(list_d, s); 

Welche auch typsicher, da Sie als Anrufer sieht nicht unbedingt wissen, was Foo wird mit seinen Parametern tun.

Also in diesem Fall haben Sie zwei scheinbar typsichere Bits Code, die zusammen am Ende Typ-unsicher sind. Das ist schlecht, weil es versteckt und daher schwer zu vermeiden und schwieriger zu debuggen ist.

+0

Ah, ich verstehe. Vielen Dank. :) –

8

überlegen Sie, ob es ...

List<Integer> nums = new ArrayList<Integer>(); 
List<Object> objs = nums 
objs.add("Oh no!"); 
int x = nums.get(0); //throws ClassCastException 

Sie würden die Lage, etwas von dem Muttertyp zu der Liste hinzufügen, die möglicherweise nicht, was es früher erklärt wurde, das als das obige Beispiel zeigt, , verursacht alle möglichen Probleme. Daher ist es nicht erlaubt.

+0

Das ist richtig, aber die Frage zeigt, dass er dies bereits versteht und wissen möchte, warum die Entscheidung getroffen wurde, dieses Verhalten zu verbieten, während andere Formen von typsicherem Verhalten noch erlaubt sind. –

+0

Ich habe dieses Beispiel bereits verstanden. Ich habe versucht, dieses Szenario in der Frage zu erklären (wie Tyler sagte), aber danke für den Kommentar. –

+1

dieser Typ ist eigentlich unsiches Verhalten * ist mit Arrays erlaubt. Das folgende kompiliert gut, aber erzeugt einen Laufzeitfehler: 'Object [] arr = new Integer [2]; arr [0] = "oh nein!"; ' – Kip

4

Sie sind nicht Subtypen voneinander, wie Generika funktionieren. Was Sie wollen, ist Ihre Funktion wie folgt zu deklarieren:

public void wahey(List<?> list) {} 

Dann wird es eine Liste von allem, was Objekt erweitert.Sie können auch tun:

public void wahey(List<? extends Number> list) {} 

Dies wird Sie in Listen von etwas, das eine Unterklasse von Nummer ist nehmen.

Ich würde empfehlen, dass Sie eine Kopie von "Java Generics und Sammlungen" von Maurice Naftalin & Philip Wadler abholen.

+0

+1, so funktioniert Generika. ** Tue ** eine Kopie von Java Generics and Collections. Tolles Buch! – WolfmanDragon

+0

Das war nicht meine Frage. Ich weiß, dass dies die Regeln der Untertypisierung mit Generika sind. –

3

Es gibt hier im Wesentlichen zwei Dimensionen der Abstraktion, die Listenabstraktion und die Abstraktion ihres Inhalts. Es ist vollkommen in Ordnung, entlang der Listenabstraktion zu variieren - zum Beispiel, dass es eine LinkedList oder eine ArrayList ist - aber es ist nicht gut, den Inhalt weiter einzuschränken, um zu sagen: Dies (Liste, die Objekte enthält) ist eine (verkettete Liste) hält nur Zahlen). Weil jeder Verweis, der es als eine (Liste, die Objekte enthält) weiß, durch den Vertrag seines Typs versteht, dass es irgendein Objekt halten kann.

Das unterscheidet sich ziemlich von dem, was Sie in dem nicht-generischen Beispielcode getan haben, wo Sie gesagt haben: Behandeln Sie diese Zeichenfolge, als wäre sie ein Double. Sie versuchen stattdessen zu sagen: behandle das (Liste, die nur Zahlen enthält) als eine (Liste, die irgendetwas enthält). Und das tut es nicht, und der Compiler kann es erkennen, also lässt es Sie nicht davonkommen.

+0

Gute Erklärung, danke. –

1

"What we are doing here is essentially the same thing, except this will pass compile-time checks and only fail at run-time. The version with Lists won't compile."

Was Sie beobachten macht Sinn, wenn man bedenkt, dass der Hauptzweck der Java Generics ist Typ Inkompatibilitäten zu erhalten bei der Kompilierung statt Laufzeit zum Scheitern verurteilt.

Von java.sun.com

Generics provides a way for you to communicate the type of a collection to the compiler, so that it can be checked. Once the compiler knows the element type of the collection, the compiler can check that you have used the collection consistently and can insert the correct casts on values being taken out of the collection.

0

In Java List<S>ist nicht ein Subtyp von List<T> wenn S ein Subtyp von T ist. Diese Regel bietet Typsicherheit.

Nehmen wir an, wir erlauben eine List<String>, ein Untertyp von List<Object> zu sein. Betrachten Sie das folgende Beispiel:

public void foo(List<Object> objects) { 
    objects.add(new Integer(42)); 
} 

List<String> strings = new ArrayList<String>(); 
strings.add("my string"); 
foo(strings); // this is not allow in java 
// now strings has a string and an integer! 
// what would happen if we do the following...?? 
String myString = strings.get(1); 

So zwingt diese Sicherheit bietet geben, aber es hat auch einen Nachteil, es ist weniger flexibel. Betrachten Sie das folgende Beispiel:

class MyCollection<T> { 
    public void addAll(Collection<T> otherCollection) { 
     ... 
    } 
} 

Sie erhalten hier eine Sammlung von T ‚s, wollen Sie alle Artikel aus einer anderen Sammlung hinzuzufügen. Sie können diese Methode nicht mit einem Collection<S> für einen S Subtyp von T aufrufen. Im Idealfall ist dies in Ordnung, da Sie nur Elemente in Ihre Sammlung einfügen, Sie ändern die Parametersammlung nicht.

Um dies zu beheben, bietet Java, was sie "Wildcards" nennen. Platzhalter sind eine Möglichkeit, Kovarianz/Kontravarianz bereitzustellen. Betrachten wir nun die folgenden mit Wildcards:

class MyCollection<T> { 
    // Now we allow all types S that are a subtype of T 
    public void addAll(Collection<? extends T> otherCollection) { 
     ... 

     otherCollection.add(new S()); // ERROR! not allowed (Here S is a subtype of T) 
    } 
} 

Jetzt, mit Wildcards wir Kovarianz in der Art T erlauben und wir blockieren Operationen, die nicht sicher sind, geben Sie (zum Beispiel das Hinzufügen eines Elements in der Sammlung). So erhalten wir Flexibilität und geben Sicherheit.

Verwandte Themen