Przypuśćmy, że mamy klasę A, a klasa B, która dziedziczy z klasy A. Powiedzmy, że mamy:
Set<A> setOfAs = new HashSet<>();
Następujące odlewanie:
((Set<B>) setOfAs)
Daje nam błąd czasu wykonywania.
Jeśli jednak używamy wieloznacznego i zdefiniować następujący zestaw:
Set<? extends A> setOfAs = new HashSet<>();
Nie mamy problemu z wytworzeniem odlewania:
((Set<B>) setOfAs)
Dlaczego dozwolony jest odlewanie kolekcji wieloznacznej, podczas rzucania kolekcji "regularny" jest zabroniony?
2 odpowiedzi
Nie mamy problemu z wytworzeniem odlewania:
Będziesz mieć niezaznaczone ostrzeżenie, więc tak naprawdę nie masz problemu; Po prostu kompilator nie może udowodnić, że to zdecydowanie się myląc i nie może umieścić niczego do byteCode, aby złapać fakt, że jest nie tak w czasie wykonywania.
A Set<? extends T>
jest Set
, gdzie można założyć, że wszyscy członkowie mogą być bezpiecznie odlewać do T
bez ClassCastException
.
A Set<? super T>
byłoby Set
, gdzie wiadomo, że jest bezpieczny, aby dodać T
bez powodowania ClassCastException
w miejscach opierających się na typach elementów w {{ X4}} Uważam, że prawidłowy termin techniczny dla tego jest bez powodowania zanieczyszczenia sterty ).
Set<T>
jest przecięciem tych dwóch ograniczonych typów: można dodać instancje T
do niego, a wszystkie elementy są instancjami T
.
Te definicje, Set<B>
może działać jako Set<? extends A>
, ponieważ wszystko, co można rzucić do B
może być również rzucony do A
.
Jednakże, Set<A>
nie może działać jako Set<B>
, ponieważ może zawierać instancje A
, które nie są instancjami B
.
Cała idea odlewania mówi: "Wiem więcej niż ty, kompilator!" Kiedy istnieje pewna niepewność co do rzeczywistego rodzaju obiektu.
W drugim przypadku sprawia, że sens. Kompilator wie, że setOfAs
jest typu Set<? extends A>
, co oznacza "A Set
nieznanego typu, a ten nieznany typ rozciąga się A
". Nie jest niepewność co typy HashSet
może być. Jeśli chodzi o kompilator, to może być HashSet<B>
...
Set<? extends A> setOfAs = new HashSet<A>();
Ale to także może być HashSet<A>
...
Set<? extends A> setOfAs = new HashSet<B>();
Ty, za pomocą odlewania, powiedzmy "Nie, setOfAs
jest HashSet<B>
". Kompilator idzie: "Cóż, to może być tak, więc zaufam ci". Niezależnie od tego, czy twoja dodatkowa wiedza jest faktycznie poprawna, jest osobną sprawą.
W pierwszym przypadku jednak setofAs
jest typu HashSet<A>
. Ponieważ zmienna typu HashSet<A>
może nigdy przechowuj obiekt typu HashSet<B>
, tj. Nie spotyka się to:
Set<A> setOfAs = new HashSet<B>();
Nie ma niepewności co do ogólnego parametru Set
. Muszę być A
. Próbując rzucić HashSet<B>
, doprowadzi tylko do kompilatora mówiącego "Nie, to może nigdy więcej!"
Podobne pytania
Powiązane pytania
Nowe pytania
java
Java to język programowania wysokiego poziomu. Użyj tego tagu, jeśli masz problemy z używaniem lub zrozumieniem samego języka. Ten tag jest rzadko używany samodzielnie i jest najczęściej używany w połączeniu z [spring], [spring-boot], [jakarta-ee], [android], [javafx], [hadoop], [gradle] i [maven].