Wyjaśnienie zasady get-put

83

Przeczytałem książkę O'Reilly, dzięki której poznałem zasadę wstępu .

  • Użyj extendssymbolu wieloznacznego, gdy otrzymujesz wartości tylko ze struktury.
  • Użyj supersymbolu wieloznacznego, gdy umieszczasz tylko wartości w strukturze.
  • I nie używaj symbolu wieloznacznego, gdy oboje chcecie pobrać i wstawić z / do struktury.

Wyjątki to:

  • Nie możesz umieścić niczego w typie zadeklarowanym za pomocą extendssymbolu wieloznacznego, z wyjątkiem wartości null, która należy do każdego typu referencyjnego.

  • Nie można uzyskać niczego z typu zadeklarowanego za pomocą supersymbolu wieloznacznego, z wyjątkiem wartości type Object, która jest nadtypem każdego typu referencyjnego.

Czy ktoś może mi pomóc zgłębić tę zasadę? Jeśli to możliwe, ułóż je hierarchicznie.

JavaResp
źródło
4
+1: Zawsze miło widzieć, jak ktoś szuka wyjaśnień na temat podstaw
wszyscy
2
@ Wszyscy, rozumiem, że masz na myśli fundament w podstawowym sensie, a nie stronę grzbietową?
Bogaty sprzedawca

Odpowiedzi:

167

Rozważ kilka bananów. Chodzi o to Collection<? extends Fruit>, że jest to zbiór określonego rodzaju owoców - ale nie wiesz (z tej deklaracji), jakiego rodzaju jest to zbiór. Możesz zdobyć z niego przedmiot i wiedzieć, że na pewno będzie to owoc, ale nie możesz do niego dodać - możesz próbować dodać jabłko do kiści bananów, co z pewnością byłoby złe. Państwo może dodać nulldo niej, jak to będzie ważna wartość dla dowolnego rodzaju owoców.

Rozważmy teraz miskę z owocami. To jest a Collection<? super Banana>, w tym sensie, że jest to zbiór pewnego typu „większy niż” Banana(na przykład Collection<Fruit>lub Collection<TropicalFruit>). Zdecydowanie możesz dodać do tego banana, ale jeśli wyjmiesz przedmiot z miski, nie wiesz, co otrzymasz - może to nie być banan. Wszystko, co na pewno wiesz, to to, że będzie to ważne (prawdopodobnie null) Objectodniesienie.

(Ogólnie rzecz biorąc, w przypadku pytań ogólnych w języku Java, często zadawane pytania dotyczące generycznych języków Java to doskonały zasób, który zawiera odpowiedzi na prawie wszystko związane z typami generycznymi, z którymi prawdopodobnie się zetkniesz).

Jon Skeet
źródło
ale podczas pobierania owocu z Kolekcji <? extends Fruits> możesz dostać dowolny owoc, ale nie banana. podobnie, wkładając do niego owoc, możesz dodać wszystko, co może nie należeć do owoców bananowca
JavaResp
6
Java uniemożliwi Ci dodanie czegokolwiek innego niż null do a Collection<? extends Fruit>właśnie z tego powodu i musiałbyś jawnie rzutować wynik pobierania elementu, właśnie z tych powodów.
Jon Skeet
@JonSkeet To może być głupie pytanie, ale w jakich przypadkach warto nie mieć „dostępu” do metod add () i get ()? Chodzi mi o to, że aby uzyskać () jakiś obiekt z listy, musisz go najpierw dodać, prawda? I na odwrót, po co miałbyś to dodawać, skoro nie możesz tego później dostać?
Timmos
7
@Timmos: Tylko dlatego, że coś musi mieć możliwość dodania wartości, nie oznacza, że cały kod musi to mieć. Na przykład, aby wyświetlić listę nazwisk osób, potrzebuję tylko Collection<? extends Person>(lub bardziej prawdopodobnie tylko Iterable<? extends Person>, ale ...). Kod tworzący tę kolekcję może wymagać, aby był to kod Collection<Employee>, ale kod konsumujący nie.
Jon Skeet,
5
@Timmos: W tym przypadku musiałbyś dokładnie powiedzieć , co masz na myśli, mówiąc „to” ... ale tak, reguły generyczne języka Java są zaprojektowane tak, aby zapewnić bezpieczeństwo typów.
Jon Skeet,