2011-09-02 17 views
5

Mam metoda, która wykorzystuje varargs wyposażone:Jak mogę przekazać zawartość listy do metody varargs?

void add(Animal ...); 

Teraz, zamiast robić .add(dog, cat), mam listę zwierzę z nieznaną liczbą elementów,

List<Animal> i = new ArrayList<Animal>(); 
i.add(dog); 
i.add(cat); 

i chce zadzwonić dodać z elementy tej listy.

Myślę, że mógłbym użyć tablicy, ale kiedy robię .add(i.toArray()), daje to błąd kompilatora.

Jaki jest właściwy sposób na zrobienie tego?

+0

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

+0

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. –

Odpowiedz

10

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()); 
} 
+0

Użyje twojej tablicy, jeśli jest wystarczająco duża lub przydzieli nową, jeśli jej nie ma. – aalku

+0

Nie otrzymasz wyjątku typograficznego po wywołaniu i.toArray (new Animal []) na liście, która nie ma ogólnego zestawu typów? –

+1

@Benjamin: nie, nie będziesz. Spróbuj uruchomić 'Tablice. asList ("cześć"). ToArray (nowy ciąg [1]); '- działa idealnie. Statycznie jest to w porządku, ponieważ ta wersja 'toArray' wybiera parametr swojego typu ze swojego parametru, a nie posiadającego' List' (dziwne, ale poprawne!), I dynamicznie, jest w porządku, ponieważ w czasie wykonywania typ 'List'' został wymazany. –

0

kiedy robię .add (i.toArray()) daje błąd, jaki jest właściwy sposób to zrobić ?

Użyj foo.addAll(i), a następnie w razie potrzeby zmień foo na tablicę.

0

Twoja metoda: void add(Animal...) oczekuje obiektu klasy Animal lub tablicy zawierającej obiekty zwierząt. Dajesz mu tablicę z obiektami klasy Object. Daj listy ogólny typ tak:

List<Animal> animals = new ArrayList<Animal>(); 
animals.add(dog); 
animals.add(cat) 

następnie zanalizować listę jako argument podczas konwertowania go do tablicy, aby metodę tak:

add(animals.toArray(new Animal[animals.size()]); 

Więcej na temat leków generycznych można znaleźć w Java API

http://download.oracle.com/javase/1,5.0/docs/guide/language/generics.html

+1

Bardziej niż oczekiwano "tablica z obiektami" Zwierzęcia "w nim, oczekuje na tablicę, której własnym typem jest" Zwierzę [] ". Forma "toArray" z argumentem zero tworzy tablicę z obiektami "Animal" w niej - tablicą, która jest w zasadzie 'new Object [] {new Animal()}'. Jednak potrzebne jest "nowe zwierzę [] {nowe zwierzę()}". Zbieżność między tablicami i rodzajami jest naprawdę zdradliwą plamą wody! –

Powiązane problemy