2009-09-30 16 views
17

Mam listę, która z pewnością zawiera tylko jeden typ obiektu. Jest to tworzone przez pewien kod źródłowy w bibliotece, którego nie mogę zaktualizować. Chcę utworzyć listę <ObjectType> na podstawie przychodzącego obiektu listy, aby mój kod wywołujący rozmawiał z listą <ObjectType>.Konwersja nietypowego typu listy na typ listy ogólnej w Javie 1.5

Jaki jest najlepszy sposób konwersji listy (lub dowolnej innej kolekcji obiektów) na listę <ObjectType>.

Odpowiedz

13

Kiedy inter-pracy z kodem starszych, które nie określają parametry typu dla typów generycznych, należy użyć symbolu wieloznacznego. Na przykład, załóżmy, że są wywołanie metody w starszej biblioteki, które po prostu zwraca surowe Collection:

Collection getItems(); 

W kodzie przypisać wynik do zmiennej zadeklarowanej asterisk:

Collection<?> items = widget.getItems(); 

ten sposób, zachowujesz bezpieczeństwo typu, więc nie otrzymasz żadnych ostrzeżeń.

Starsza wersja może określać (w komentarzu, najprawdopodobniej), jakie powinny być parametry ogólne. Na przykład:

/** 
* @return the items, as a Collection of {@link Item} instances. 
*/ 
Collection getItems(); 

W tym przypadku masz wybór. Możesz może rzucić wynik do Collection<Item>, ale jeśli to zrobisz, polegasz w 100% na bibliotece strony trzeciej i odrzucasz pewność, że typy generyczne Java: że dowolny ClassCastException podniesiony w czasie wykonywania nastąpi bezpośrednio po jawnym odlew.

Co zrobić, jeśli nie ufasz w pełni bibliotece firmy zewnętrznej, ale nadal musisz wygenerować numer Collection<Item>? Następnie utwórz nową kolekcję i dodaj zawartość po przeniesieniu ich do oczekiwanego typu. W ten sposób, jeśli w bibliotece wystąpi błąd, od razu się o tym dowiesz, zamiast mieć jakiś kod daleko i znacznie później wysadzić w powietrze tajemnicę ClassCastException.

Na przykład:

Collection<?> tmp = widget.getItems(); 
Collection<Item> items = new ArrayList<Item>(tmp.size()); 
for (Object o : tmp) 
    items.add((Item) o); /* Any type error will be discovered here! */ 

Dla przypadku, gdy parametr typu nie jest znany w czasie kompilacji, można użyć type-checked collection factories klasy Collections.

+0

Problem polega na tym, że tak naprawdę nie zyskuje nic innego jak wyciszanie ostrzeżeń "surowego typu". Konwersja na leki generyczne wymagałaby korzystania z jej zalet! –

+1

Jakie są korzyści z leków generycznych? Nie powinno to sprawiać, że Twój kod wygląda ładnie i wymaga mniej pisania! Oto, co następuje: * Twój kod jest bezpieczny, jeśli kompiluje się bez ostrzeżeń. * To wszystko. Ignorując lub ukrywając ostrzeżenia, równie dobrze możesz nie używać generycznych, ponieważ wszystko, co robisz, tworzy sytuacje, w których kod bez operatora obsady w tajemniczy sposób podnosi "ClassCastException". – erickson

11

Można po prostu rzucić listę:

List raw = new ArrayList(); 
    List<String> generic = (List<String>) raw; 
+2

Jeśli lista rzeczywiście zawiera jeden rodzaj towaru, jest to dobra odpowiedź. –

+1

To jest duże "jeśli". To zależy w dużym stopniu od kontekstu. – erickson

+0

Mogę zagwarantować, że lista będzie zawierała jeden typ przedmiotu. To był kod napisany w pre-generics Java 1.4. –

1

Najlepszym i najbezpieczniejszym sposobem jest użycie metody java.util.Collections „checkedList (LIST typu Class)”

Dzięki tej metodzie, wszystkie elementy w swojej starej listy zostaną sprawdzone już w możliwy.

+0

Czy "checkedList" w Javie 5 nie dotyczy tylko nowych (i pustych) list ogólnych? Czy sugerujesz, abyśmy użyli nie-ogólnej "listy kontrolnej" przed Java 5? Ten starszy formularz nie zostanie przekształcony w ogólną listę. –

0

Jeśli po prostu rzucisz na List<T> w jakimkolwiek starym miejscu, otrzymasz ostrzeżenie "niezaznaczone" kompilatora. Rozwiązaliśmy to, przenosząc go na metodę użyteczności.

public class Lists { 
    @SuppressWarnings({"unchecked"}) 
    public static <T> List<T> cast(List<?> list) { 
     return (List<T>) list; 
    } 
} 

Dzwoniący nie otrzymuje teraz ostrzeżenia, np.:

for (Element child : Lists.<Element>cast(parent.getChildren())) { 
    // ... 
} 

To checkedList narzędzie jest w teorii to świetny pomysł, ale w praktyce to jest do bani, aby przejść do klasy można oczekiwać. Mam nadzieję, że Java w końcu otrzyma ogólne informacje o typowaniu.

1

Spróbuj tego:

List<ObjectType> objectsWithType = Arrays.asList((ObjectType[])wildcardObjects).toArray()); 

Należy jednak pamiętać, że to przyniesie stały Lista długości. Jeśli spróbujesz dodać lub usunąć element z tej listy, spowoduje to błąd. Dlatego należy zachować ostrożność podczas korzystania z Arrays.asList().

Powiązane problemy