Aby w pełni zrozumieć główny powód takiego stanu rzeczy, potrzebny jest kontekst.
Prymitywy a klasy
Zmienne pierwotne w Javie zawierają wartości (liczbę całkowitą, liczbę binarną zmiennoprzecinkową podwójnej precyzji itp.). Ponieważ te wartości mogą mieć różne długości , zawierające je zmienne mogą również mieć różne długości (rozważ w float
porównaniu double
).
Z drugiej strony zmienne klasowe zawierają odniesienia do instancji. Odnośniki są zwykle implementowane jako wskaźniki (lub coś bardzo podobnego do wskaźników) w wielu językach. Te rzeczy mają zwykle ten sam rozmiar, niezależnie od wielkości tych przypadkach, których dotyczą ( Object
, String
, Integer
, etc).
Ta właściwość zmiennych klasowych sprawia, że zawarte w nich odwołania są wymienne (do pewnego stopnia). To pozwala nam robić to, co nazywamy substytucją : mówiąc ogólnie, używać instancji określonego typu jako instancji innego, pokrewnego typu ( na przykład użyj a String
jako Object
).
Zmienne pierwotne nie są zamienne w ten sam sposób, ani między sobą, ani z Object
. Najbardziej oczywistym powodem tego (ale nie jedynym) jest różnica w wielkości. To sprawia, że typy prymitywne są pod tym względem niewygodne, ale nadal potrzebujemy ich w języku (z powodów, które sprowadzają się głównie do wydajności).
Typy ogólne i usuwanie typów
Typy ogólne to typy z co najmniej jednym parametrem typu (dokładna liczba nazywana jest liczbą ogólną ). Na przykład definicja typu ogólnego List<T>
ma parametr typu T
, którym może być Object
(tworzenie konkretnego typu List<Object>
), String
( List<String>
), Integer
(List<Integer>
) i tak dalej.
Typy ogólne są o wiele bardziej skomplikowane niż nieogólne. Kiedy zostały wprowadzone do Javy (po jej pierwszym wydaniu), aby uniknąć radykalnych zmian w JVM i być może zerwania kompatybilności ze starszymi plikami binarnymi, twórcy Javy zdecydowali się zaimplementować typy generyczne w jak najmniej inwazyjny sposób: wszystkie konkretne typy List<T>
są w rzeczywistości skompilowane do (binarnego odpowiednika) List<Object>
(dla innych typów powiązanie może być czymś innym niż Object
, ale o co chodzi). W procesie tym następuje utrata ogólnych informacji o wartościach i parametrach typu , dlatego nazywamy to wymazywaniem typu .
Łącząc te dwie rzeczy razem
Teraz problem jest kombinacja powyższych realia: jeśli List<T>
staje się List<Object>
we wszystkich przypadkach, po czym T
zawsze musi być typu, które mogą być bezpośrednio przypisaneObject
. Nie można pozwolić na nic innego. Ponieważ, jak już powiedzieliśmy, int
, float
i double
nie są wymienne z Object
, tam nie może być List<int>
, List<float>
lubList<double>
(chyba znacznie bardziej skomplikowane wdrożenie generycznych istniał w JVM).
Ale Java oferty rodzaje podoba Integer
, Float
a Double
który zawijać tych prymitywów w instancji klasy, dzięki czemu skutecznie jako substytucyjne Object
, a tym samym pozwalając typy generyczne pośrednio pracy z prymitywów , jak również (bo może mieć List<Integer>
, List<Float>
,List<Double>
i tak dalej).
Proces tworzenia Integer
ze związku int
, A Float
od A float
i tak dalej, nazywany jest boks . Odwrotność nazywa się unboxing . Ponieważ konieczność zaznaczania prymitywów za każdym razem, gdy chcesz ich używać, Object
jest niewygodna, są przypadki, w których język robi to automatycznie - nazywa się to autoboxingiem .