Warum ist ListNumber kein Untertyp von ListObject?

8
%Vor%

Der Aufruf der Methode wird nicht überprüft. Ich kann den Parameter nicht einmal wie folgt umsetzen:

%Vor%

Aus meiner Forschung habe ich herausgefunden, dass der Grund dafür, dass dies nicht erlaubt ist, die Typensicherheit ist. Wenn wir das oben Gesagte tun könnten, könnten wir folgendes haben:

%Vor%

Innerhalb der Methode wahey könnten wir einige Strings zur Eingabeliste hinzufügen (da der Parameter eine List<Object> -Referenz beibehält). Nach dem Methodenaufruf verweist ld jetzt auf eine Liste mit dem Typ List<Double> , aber die tatsächliche Liste enthält einige String-Objekte!

Dies scheint anders zu sein als bei Java ohne Generika. Zum Beispiel:

%Vor%

Was wir hier machen, ist im Wesentlichen das Gleiche, außer dass es Prüfungen zur Kompilierungszeit bestehen und nur zur Laufzeit fehlschlagen wird. Die Version mit Listen wird nicht kompiliert.

Dies lässt mich glauben, dass dies eine reine Designentscheidung in Bezug auf die Typenzuschläge für Generika ist. Ich hatte gehofft, einige Kommentare zu dieser Entscheidung zu bekommen?

    
Jack Griffith 06.08.2009, 17:29
quelle

6 Antworten

9

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

%Vor%

Was sich auf die gleiche Weise verhält (kompiliert, aber zur Laufzeit nicht funktioniert). Der Grund dafür, dass Sie das gewünschte Verhalten nicht zulassen, liegt darin, dass implizite type-unsafe-Aktionen zulässig sind, die im Code viel schwieriger zu bemerken sind. Zum Beispiel:

%Vor%

Das sieht vollkommen gut und typsicher aus, bis man es so nennt:

%Vor%

Das sieht auch typsicher aus, weil Sie als Aufrufer nicht unbedingt wissen, was Foo mit seinen Parametern machen wird.

In diesem Fall haben Sie also zwei scheinbar typsichere Code-Teile, die am Ende typsicher sind. Das ist schlecht, weil es versteckt und daher schwer zu vermeiden und schwieriger zu debuggen ist.

    
Tyler McHenry 06.08.2009, 17:37
quelle
8

Überlegen Sie, ob es ...

war %Vor%

Sie könnten der Liste einen beliebigen Typ des übergeordneten Typs hinzufügen, der möglicherweise nicht dem entspricht, für den er zuvor deklariert wurde, was, wie im obigen Beispiel gezeigt, alle möglichen Probleme verursacht. So ist es nicht erlaubt.

    
James 06.08.2009 17:35
quelle
4

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

%Vor%

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

%Vor%

Damit können Sie Listen von etwas aufnehmen, das eine Unterklasse von Number ist.

Ich empfehle Ihnen, eine Ausgabe von "Java Generics and Collections" von Maurice Naftalin & amp; Philip Wadler.

    
Norman 06.08.2009 17:38
quelle
3

Hier gibt es 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). Denn jede Referenz, die sie als eine (Liste, die Objekte enthält) kennt, versteht durch den Vertrag ihres Typs, dass sie irgendein Objekt enthalten kann.

Das ist ganz anders als das, was Sie im Beispielcode für Nicht-Generika getan haben, wo Sie gesagt haben: Behandeln Sie diesen String so, als ob er ein Double wäre. 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.

    
Carl Manaster 06.08.2009 17:40
quelle
1
  

"Was wir hier machen, ist im Wesentlichen   das Gleiche, außer dass das passieren wird   Kompilierzeitprüfungen und scheitern nur bei   Laufzeit. Die Version mit Listen wird nicht   kompilieren. "

Was Sie beobachten, ist sehr sinnvoll, wenn Sie bedenken, dass der Hauptzweck von Java-Generierungen darin besteht, dass Typinkompatibilitäten bei der Kompilierung anstatt bei der Laufzeit fehlschlagen.

Von java.sun.com

  

Generics bietet eine Möglichkeit für Sie   den Typ einer Sammlung mitteilen   an den Compiler, so dass es sein kann   überprüft. Sobald der Compiler die   Elementtyp der Sammlung, der   Compiler kann überprüfen, dass Sie verwendet haben   die Sammlung konsequent und kann   Fügen Sie die richtigen Umwandlungen für Werte ein   aus der Sammlung genommen werden.

    
Graphics Noob 06.08.2009 19:11
quelle
0

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

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

%Vor%

Also, dies zu erzwingen, bietet Sicherheit, aber es hat auch einen Nachteil, es ist weniger flexibel. Betrachten Sie das folgende Beispiel:

%Vor%

Hier haben Sie eine Sammlung von T s, Sie möchten alle Elemente aus einer anderen Sammlung hinzufü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 das zu beheben, stellt Java sogenannte "Wildcards" zur Verfügung. Platzhalter sind eine Möglichkeit, Kovarianz / Kontravarianz bereitzustellen. Betrachten Sie nun folgendes mit Platzhaltern:

%Vor%

Nun erlauben wir mit Platzhaltern die Kovarianz im Typ T und blockieren Operationen, die nicht typsicher sind (zum Beispiel das Hinzufügen eines Elements zur Sammlung). Auf diese Weise erhalten wir Flexibilität und geben Sicherheit.

    
aromero 26.06.2012 03:05
quelle

Tags und Links