Ist die Rückwärtskompatibilität mit älteren (nicht generischen) Versionen von Collection
aufrechtzuerhalten? Oder gibt es ein subtileres Detail, das mir fehlt? Ich sehe dieses Muster wiederholt in remove
auch (remove(Object o)
), aber add
wird als add(E e)
generalisiert.Warum haben wir enthält (Objekt o) statt enthält (e e)?
Antwort
benötigt eine Object
, weil das Objekt, mit dem es übereinstimmt, nicht vom selben Typ sein muss wie das Objekt, das Sie an übergeben; es erfordert nur, dass sie gleich sind. Von der Spezifikation gibt contains(o)
den Wert true zurück, wenn ein Objekt e
vorhanden ist, so dass (o==null ? e==null : o.equals(e))
wahr ist.Beachten Sie, dass nichts o
und e
vom gleichen Typ sein muss. Dies ergibt sich aus der Tatsache, dass die equals()
-Methode einen Object
als Parameter verwendet, nicht nur den gleichen Typ wie das Objekt.
Obwohl es allgemein zutreffend sein kann, dass viele Klassen equals()
definiert haben, so dass ihre Objekte nur Objekten ihrer eigenen Klasse entsprechen können, ist das sicherlich nicht immer der Fall. Zum Beispiel sagt die Spezifikation für List.equals()
, dass zwei List
Objekte gleich sind, wenn sie beide List
s sind und den gleichen Inhalt haben, auch wenn sie verschiedene Implementierungen von List sind. Also zurück zu dem Beispiel in dieser Frage, ist es möglich, eine Collection<ArrayList>
und für mich mit einem LinkedList
als Argument zu haben, und es möglicherweise True zurückgegeben, wenn es eine Liste mit dem gleichen Inhalt ist. Dies wäre nicht möglich, wenn generisch wäre und sein Argumenttyp auf E
beschränkt wäre.
In der Tat, die Tatsache, dass jedes Objekt als Argument erlaubt eine interessante Anwendung, wo Sie können, um es für die Existenz eines Objekts in der Sammlung zu testen, die eine bestimmte Eigenschaft erfüllt:
Collection<Integer> integers;
boolean oddNumberExists = integers.contains(new Object() {
public boolean equals(Object e) {
Integer i = (Integer)e;
if (i % 2 != 0) return true;
else return false;
}
});
Auch diese Methodensignatur 'enthält (Objekt o)' bietet eine wirklich schöne Waffe um sich bequem in einen Fuß zu schießen. Diese Methode ist wirklich ein Paradebeispiel für die Einschränkung von Java Generics. –
Es ist, weil die contains
Funktion die equals
Funktion nutzt, und die equals
Funktion in der Basisobjektklasse mit einer Signatur von equals(Object o)
anstatt equals(E e)
definiert (da nicht alle Klassen sind generisch). Gleicher Fall mit der Funktion remove
- es durchläuft die Sammlung mit der equals
-Funktion, die ein Object-Argument übernimmt.
Dies erklärt die Entscheidung jedoch nicht direkt, da sie möglicherweise noch den Typ E verwendet hätten und es automatisch für die Eingabe von Object beim Aufruf von equals
umgewandelt hätte; aber ich stelle mir vor, sie wollten die Funktion für andere Objekttypen aufrufen lassen. Es ist nichts falsch daran, eine Collection<Foo> c;
und dann rufen c.contains(somethingOfTypeBar)
- es wird immer falsch, und so beseitigt es die Notwendigkeit für eine Besetzung zu Foo (die eine Ausnahme auslösen kann) oder, um vor der Ausnahme zu schützen, eine typeof
Anruf. Sie können sich also vorstellen, wenn Sie über etwas mit gemischten Typen iterieren und contains
für jedes der Elemente aufrufen, können Sie einfach die contains-Funktion für alle verwenden, anstatt Wächter zu benötigen.
Es ist eigentlich erinnert an den „neueren“ lose typisierte Sprachen, wenn Sie es sehen auf diese Weise ...
Dies hat nichts zu tun mach mit dem wahren Grund. Es wäre viel schöner, eine Art von Typprüfung auf 'contains' und vielleicht' remove' zu haben. Es wäre viel weniger fehleranfällig gewesen. –
"es wird immer falsch zurückgegeben" nein wird es nicht. es ist durchaus möglich, dass eine Klasse ein Objekt einer anderen Klasse egalisiert – newacct
hier beantwortet.
Why aren't Java Collections remove methods generic?
Kurz gesagt, sie wollten die Rückwärtskompatibilität maximieren, weil Sammlungen lange vor Generika eingeführt wurden.
Und von mir hinzufügen: das Video, das er bezieht, ist es wert, zu sehen.
http://www.youtube.com/watch?v=wDN_EYUvUq0
Update
Um zu klären, der Mann, der sagte, dass (im Video) war einer der Menschen, die Java-Karten und Sammlungen aktualisiert Generika zu verwenden. Wenn er es nicht weiß, wer dann?
Da es sonst nur mit der genauen Übereinstimmung des Parametertyps verglichen werden könnte, hätten speziell wildbehinderte Sammlungen nicht mehr funktioniert, z.
class Base
{
}
class Derived
extends Base
{
}
Collection< ? extends Base > c = ...;
Derived d = ...;
Base base_ref = d;
c.contains(d); // Would have produced compile error
c.contains(base_ref); // Would have produced compile error
EDIT
Für Zweifler, die denken, das ist nicht einer der Gründe dafür, hier wird eine modifizierte Array-Liste mit einem generified würde enthält Methode
class MyCollection<E> extends ArrayList<E>
{
public boolean myContains(E e)
{
return false;
}
}
MyCollecttion< ? extends Base > c2 = ...;
c2.myContains(d); // does not compile
c2.myContains(base_ref); // does not compile
Grundsätzlich contains(Object o)
ist ein Hack zu machen dieser sehr häufige Anwendungsfall, um mit Java Generics zu arbeiten.
Pflege, um downvote zu erklären? –
Im normalen Szenario würde niemand eine Sammlung in 'Collection
@Jai. Hier ist ein Szenario 'void myMethod (Sammlung Erweitert Foo> coll)'. Wenn Sie innerhalb dieser Sammlung sehen müssen, ob eine Verison von 'Foo' in dieser Sammlung enthalten ist, würden Sie die in dieser Antwort beschriebene Einschränkung erreichen. –
"enthält dieser Korb Äpfel diese Orange?"
klar eine echte Antwort kann nicht gegeben werden. aber das lässt immer noch zu möglichkeiten:
- die antwort ist FALSCH.
- die Frage ist nicht gut gebildet, sollte es nicht kompilieren übergeben.
die Sammlung api wählte die erste. aber die 2. Wahl wäre auch vollkommen sinnvoll. Eine Frage wie diese ist 99,99% der Fälle eine Schwachsinnfrage, also fragt nicht einmal!
Die Frage sollte nicht als schlecht geformt angesehen werden, wenn z.B. hat zwei Körbe, die Früchte enthalten und will wissen, ob Früchte in einem Korb mit Früchten in dem anderen übereinstimmen. Wenn man wüsste, dass ein Korb nur Äpfel und nur Orangen enthält, kann es sinnvoll sein, die Suche nach einem Streichholz kurzzuschließen, aber man nimmt an, dass ein Korb nur Äpfel und der andere nur gemischte Früchte enthielt. Den Apfelkorb nach jeder Frucht im anderen Korb zu fragen, ohne zuerst seinen Typ zu überprüfen, wäre einfacher, als jede Frucht zu prüfen, bevor man fragt, ob es ein Apfel ist. – supercat
In meinem Beispiel ist der Parameter bekanntlich eine Orange, daher klingt die Frage lächerlich. In Ihrem Beispiel wäre die Frage: "Hat der Korb mit Äpfeln diese Frucht?", das ist legitim.der Anwendungsfall ist jedoch seltener. Wir können die API so umgestalten, dass Sie Ihre Frage zulassen und gleichzeitig meine Frage verbieten können, indem Sie den Parametertyp auf Super-Apple-Typen beschränken. – irreputable
Es gibt keinen Mechanismus in .Net, über den eine Methode einen generischen oder anderen Parameter als Supertyp eines anderen Typs einschränken kann, und ich denke nicht, dass Java auch einen solchen Mechanismus besitzt. Solch eine Sache würde dazu neigen, das Liskow-Substitutionsprinzip zu verletzen, da eine Methode, die mit 'Fruit' verwendet werden kann, mit' Orange' verwendet werden kann. Es gibt Möglichkeiten in .Net, über die man "Veraltete" Tags verwenden könnte, um Compiler-Squawks in bestimmten statisch identifizierbaren, dummen Fällen auszulösen, aber ich würde denken, dass das verwirrender als hilfreich wäre. – supercat
- 1. MailChimp (Mandrill) für .NET warum E-Mail enthält Bild?
- 2. Ansichtsmodell enthält keine Definition für E-Mail
- 3. Warum ist die Zeitkomplexität für BFS/DFS nicht einfach O (E) anstatt O (E + V)?
- 4. Enthält der Verzweigungsvorhersager in seiner Vorhersage auch E/A-Anweisungen?
- 5. Objekt enthält keine Definition für „Eigenschaften“ enthält
- 6. Sollen wir standardmäßig asynchrone E/A verwenden?
- 7. Prüfen, ob eine Zeichenfolge eine E-Mail-Adresse enthält?
- 8. E-Mail senden mit Exchange-Webserver mit Körper enthält URL
- 9. Löschen einer E-Mail, wenn Betreff bestimmte Wörter enthält
- 10. Herunterladen E-Mail Körper Inline-Bilder in Java enthält
- 11. Wie überprüft man, ob eine Zeichenfolge eine E-Mail enthält?
- 12. Warum haben wir Redis, wenn wir MySQL temporäre Tabellen haben?
- 13. Gson.toJson Objekt enthält URL
- 14. Swift 2 Array Enthält Objekt?
- 15. Warum enthält eine Schnittstelle keine Eigenschaften
- 16. Warum enthält vielleicht Just?
- 17. Warum verwendet dieser Ereignishandler "e = e || event"?
- 18. Verwendung enthält statt stringStartsWith Knockout js
- 19. Android Image enthält zwei Bilder statt einer
- 20. Was enthält das Hibernate-Proxy-Objekt?
- 21. Warum enthält mein JSON, das HTML enthält, Fehler?
- 22. Kann jemand bitte e = e || erklären x? Warum e zu e zuordnen?
- 23. Bestellung senden an E-Mail statt auschecken
- 24. JWTAuth Authentifizierung mit Benutzername statt E-Mail
- 25. Django Rest Auth E-Mail statt Benutzername
- 26. Warum CSS enthält() funktioniert nicht mit Winkelmesser?
- 27. Warum enthält cmake_link_libraries statische Bibliotheken?
- 28. Warum enthält Doctrine \ ORM \ Configuration "DoctrineProxies" -Objekt das Universum?
- 29. enthält
- 30. Warum haben wir eine unveränderliche leere Karte?
möglich Duplikat von [Warum sind Java-Sammlungen nicht Methoden generisch entfernen?] (Http://StackOverflow.com/questions/104799/why-arent-java-collections-remove-methods-generic) – newacct