Dlaczego tak się ArrayList<Integer>[] arr=new ArrayList<Integer>[40];
dzieje , gdy próbuję utworzyć tablicę ArrayLists: występuje błąd, a Java nie pozwala na to?
Czy istnieje powód związany z implementacją generycznych w Javie, generycznych w dowolnym języku lub czegoś arbitralnego?
java
language-design
generics
Jakob Weisblat
źródło
źródło
Odpowiedzi:
Jest to jedna z głównych dziur w ogólnych wersjach Javy, tablice są kowariantne , co oznacza, że tablica typu
Foo[]
jest podklasąObject[]
iParentOfFoo[]
. Porównaj to z tym,List<Foo>
co nie ma tego zachowania.Było to ważne, gdy Java nie miała generycznych (aż do Java 5), ponieważ w przeciwnym razie coś w rodzaju ogólnej funkcji sortowania było po prostu niemożliwe.
Ma jednak ten trudny problem, który polega na tym, że tablice lubią wiedzieć, jakiego typu są w środowisku wykonawczym . Jednak generics w Javie opiera się na usuwaniu typu. Te dwie rzeczy w ogóle nie pasują do siebie i do tego dochodzi nasz problem.
Długa i krótka to, w Javie 1, tablice kowariantne częściowo wypełniały dziurę, którą stworzył brak generyków. Jednak gdy próbowali poprawnie wypełnić tę dziurę, zgodność wsteczna oznaczała, że tablice były prawie niemożliwe do wdrożenia.
W rzeczywistości facet, który faktycznie stworzył platformę generyczną, Martin Odersky, mówił o tym tutaj podczas wywiadu, dlaczego stworzył Scalę. (Całkiem fascynujące, jeśli w ogóle interesujesz się historią Scali)
źródło
W rzeczywistości jest to nieco arbitralne.
Problem polega na tym, że umożliwia on otwór w systemie typów, ponieważ
ArrayList<T>[]
można go rzucić,Object[]
a następnie można wstawićArrayList<U>
tablicę, gdzieU != T
.Projektanci Java postanowili zablokować tę dziurę tak chętnie, jak to możliwe, nie pozwalając
new ArrayList<T>[N]
wcale.Jednak można go również podłączyć, nie zezwalając na upcasting tablic ogólnych (bez ostrzeżenia „niezaznaczonego”).
źródło
Integer
Object[]
String[]
ponieważ tablica jest kowariantna, przy czym każdy typ jest podklasą obiektu, co powoduje błąd w czasie wykonywania z powodu wyjątku rzutowania. podczas gdy rodzajowy jest niezmienny, więc gdy buduje na typie, upewnij się, że jest bezpieczny, więc jeśli typ inny niż ten tworzy typ, to daje błąd kompilatora.
źródło