Erklärung des Get-Put-Prinzips

82

Ich habe das O'Reilly-Buch gelesen, indem ich dieses Get-Put-Prinzip kennengelernt habe .

  • Verwenden Sie einen extendsPlatzhalter , wenn Sie nur bekommen Werte aus einer Struktur.
  • Verwenden Sie einen superPlatzhalter , wenn Sie nur setzen Werte in eine Struktur.
  • Verwenden Sie keinen Platzhalter, wenn Sie beide von / zu einer Struktur abrufen und dort ablegen möchten.

Ausnahmen sind:

  • Sie können nichts in einen mit einem extendsPlatzhalter deklarierten Typ einfügen, außer den Wert null, der zu jedem Referenztyp gehört.

  • Sie können aus einem mit einem superPlatzhalter deklarierten Typ nichts herausholen, außer einem Wert vom Typ Object, der ein Supertyp für jeden Referenztyp ist.

Kann mir jemand helfen, diese Regel eingehend zu untersuchen? Wenn möglich, setzen Sie sie bitte hierarchisch.

JavaResp
quelle
4
+1: Es ist immer schön zu sehen, dass jemand Klarheit über ein Fundament sucht
Jeder
2
@Jeder, ich nehme an, Sie meinen Fundament eher im grundlegenden Sinne als auf der dorsalen Seite?
Rich Seller

Antworten:

164

Betrachten Sie ein paar Bananen. Dies ist Collection<? extends Fruit>insofern eine Sammlung einer bestimmten Obstsorte - aber Sie wissen (aus dieser Erklärung) nicht, um welche Obstsorte es sich handelt. Sie können erhalten Sie ein Element aus und es weiß , es wird auf jeden Fall eine Frucht sein, aber Sie können nicht hinzufügen , um es - Sie könnten versuchen , einen Apfel zu einem Bündel Bananen hinzuzufügen, die auf jeden Fall falsch wäre. Sie können es ergänzen null, da dies ein gültiger Wert für jede Art von Obst ist.

Betrachten Sie nun eine Obstschale. Dies ist Collection<? super Banana>insofern eine Sammlung eines Typs, der "größer als" ist Banana(zum Beispiel Collection<Fruit>oder Collection<TropicalFruit>). Sie können definitiv eine Banane hinzufügen, aber wenn Sie einen Gegenstand aus der Schüssel holen, wissen Sie nicht, was Sie bekommen - es kann durchaus keine Banane sein. Alles, was Sie sicher wissen, ist, dass es sich um eine gültige (möglicherweise null) ObjectReferenz handelt.

(Im Allgemeinen ist die Java Generics-FAQ für Fragen zu Java-Generika eine hervorragende Ressource, die die Antwort auf fast alles enthält, was mit Generika zu tun hat.)

Jon Skeet
quelle
Aber während Sie eine Frucht aus der Sammlung holen <? erweitert Früchte>, können Sie jede Frucht bekommen, nicht die Banane. In ähnlicher Weise können Sie, während Sie eine Frucht hinzufügen, alles hinzufügen, was möglicherweise nicht zu Bananenfrüchten gehört
JavaResp
6
Java verhindert, dass Sie aus Collection<? extends Fruit>genau diesem Grund etwas anderes als null zu a hinzufügen , und Sie müssen das Ergebnis des Abrufs eines Elements aus genau diesen Gründen explizit umwandeln.
Jon Skeet
@ JonSkeet Dies mag eine dumme Frage sein, aber in welchen Fällen ist es nützlich, keinen "Zugriff" auf die Methoden add () und get () zu haben? Ich meine, um () ein Objekt aus einer Liste zu entfernen, müssen Sie es zuerst hinzufügen, oder? Und umgekehrt, warum sollten Sie es hinzufügen, wenn Sie es danach nicht mehr bekommen können?
Timmos
7
@Timmos: Nur weil etwas in der Lage sein muss, einen Wert hinzuzufügen, heißt das nicht, dass der gesamte Code dazu in der Lage sein muss. Zum Beispiel, um eine Liste von Personennamen anzuzeigen, brauche ich möglicherweise nur einen Collection<? extends Person>(oder wahrscheinlicher nur einen Iterable<? extends Person>, aber ...). Der Code , der diese Sammlung erstellt, muss möglicherweise ein Code sein Collection<Employee>, der konsumierende Code jedoch nicht.
Jon Skeet
5
@Timmos: In diesem Fall müssten Sie genau sagen , was Sie mit "es" gemeint haben ... aber ja, die Regeln von Java-Generika sollen Typensicherheit bieten.
Jon Skeet