To:
add(i.toArray(new Animal[i.size()]))
List.toArray zwraca Object[]
, niezależnie od typu argumentu na liście: chociaż można napisać new List<String>().toArray()
, dostaniesz Object[]
. Jednak version of toArray that takes an array to fill zwraca tablicę z poprawnym typem: jeśli napiszesz new List<String>().toArray(new String[0])
, otrzymasz numer String[]
. Zwróć uwagę, że rozmiar przekazywanej macierzy nie musi nawet odpowiadać rozmiarowi listy, chociaż dobrą praktyką jest upewnienie się, że tak jest.
Jest to ostatecznie spowodowane łagodną cechą generycznych. Na pierwszy rzut oka możesz pomyśleć, że String[]
i List<String>
oznaczają podobne rzeczy dla swoich typów bazowych - jeden to tablica łańcuchów, a druga to lista ciągów.
Są one jednak w rzeczywistości bardzo różne.
Tablica jest prymitywem językowym i ma swój typ w niej zapakowany. Jeśli wziąłeś edytor heksadecymalny i spojrzałeś na instancję tablicy w pamięci JVM, byłbyś w stanie znaleźć (gdzieś w pobliżu) zapis rodzaju obiektów, które posiada. Oznacza to, że jeśli wziąłeś instancję tablicy o nieznanym typie komponentu, możesz find out what that type is. Odwrotnie oznacza to, że jeśli zamierzasz create an instance of an array, musisz wiedzieć, jaki typ komponentu chcesz.
List
, z drugiej strony, używa rodzajowych, które w Javie jest realizowany przy type erasure, co oznacza, że z grubsza rzecz biorąc, jest to coś, co istnieje w kompilator, ale nie w czasie wykonywania (kompilator może sprawdzić, czy dobrze, ale JVM nie może). Prowadzi to do prostej i wydajnej implementacji (jeden dość prosty, aby dodać go do pre-generics Java bez zmiany JVM), ale ma pewne braki - w szczególności, że w czasie wykonywania, nie ma sposobu, aby powiedzieć, jaki typ argumentu na dowolnym wystąpieniu klasy ogólnej jest, ponieważ argumenty typu istnieją tylko w kompilatorze. Ponieważ do instancji List
służy obsługa toArray()
, jedyne, co może zrobić, to utworzyć Object[]
. Po prostu nie zna bardziej konkretnego typu.
Jednym ze sposobów patrzenia na to, że tablice mają typu argumentu jako część ich klasy, natomiast List
s mieć typ argumentu jako część ich typu, a ponieważ obiekty mają zajęcia, ale zmienne mają typy, nie można uzyskać argumentu typu obiektu List
od obiektu, tylko ze zmiennej przechowującej obiekt (jako na bok, nie można również pobrać argumentu typu tablicy ze zmiennej przechowującej tablicę (należy rozważyć Object[] array = new String[0];
), ale to nie ma znaczenia, ponieważ zmienna pozwala uzyskać obiekt - chyba że jest pusty).
Do tego sprowadzają się do kodu, problem jest:
public <E> E[] createSimilarlyTypedArray(List<E> list) {
Class<E> componentType = list.???; // there is no way to do this
return Arrays.newInstance(componentType, list.size());
}
Nie mogę zrozumieć pytania. Zrobiłeś własną metodę'add (Animal ...) 'ale dzwonisz do ArrayList.add (Object), a nie do własnego. Dlaczego? Edytuj pytanie w kontekście kodu. Czy ten blok kodu znajduje się w twojej metodzie'add '? Jeśli Twoim jedynym problemem jest to, że nie możesz rzucić Object [] na Animal [], to wykonaj odpowiedź @Tom. – aalku
Notatka na przyszłość: Jeśli masz błąd kompilatora, skopiuj cały komunikat o błędzie, a także linie kodu źródłowego dotyczące tej wiadomości. –