To jest uproszczona wersja omawianego kodu, jedna klasa ogólna używa innej klasy z parametrami typu ogólnego i musi przekazać jeden z typów ogólnych do metody z parametrami varargs:
class Assembler<X, Y> {
void assemble(X container, Y... args) { ... }
}
class Component<T> {
void useAssembler(T something) {
Assembler<String, T> assembler = new Assembler<String, T>();
//generates warning:
// Type safety : A generic array of T is
// created for a varargs parameter
assembler.assemble("hello", something);
}
}
Czy istnieje poprawny sposób przekazania parametru ogólnego do metody varargs bez napotkania tego ostrzeżenia?
Oczywiście coś takiego
assembler.assemble("hello", new T[] { something });
nie działa, ponieważ nie można tworzyć tablic ogólnych.
Odpowiedzi:
Poza dodaniem
@SuppressWarnings("unchecked")
nie sądzę.Ten raport o błędzie zawiera więcej informacji, ale sprowadza się do tego, że kompilator nie lubi tablic typów ogólnych.
źródło
Tom Hawtin zwrócił na to uwagę w komentarzu, ale żeby być bardziej wyraźnym: tak, możesz rozwiązać ten problem w witrynie deklaracji (zamiast (potencjalnie wielu) witryn wywołania): przełącz na JDK7.
Jak widać w poście na blogu Josepha Darcy'ego , ćwiczenie Project Coin, mające na celu wybranie niewielkich, przyrostowych ulepszeń języka dla Java 7, przyjęło propozycję Boba Lee, aby zezwolić na coś podobnego
@SuppressWarnings("varargs")
po stronie metody, aby ostrzeżenie zniknęło w sytuacjach, w których było wiadomo bezpieczny.Zostało to zaimplementowane w OpenJDK z tym zatwierdzeniem .
Może to być przydatne lub nie dla twojego projektu (wiele osób nie byłoby szczęśliwych, gdyby przełączyło się na przedpremierową niestabilną wersję JVM!), Ale być może tak jest - a może ktoś, kto znajdzie to pytanie później (po wydaniu JDK7 ) uzna to za przydatne.
źródło
Jeśli szukasz interfejsu płynnego, możesz wypróbować wzorzec konstruktora. Nie tak zwięzłe jak varargs, ale jest bezpieczne dla typów.
Statyczna metoda oparta na typie ogólnym może wyeliminować część schematu podczas korzystania z konstruktora, zachowując jednocześnie bezpieczeństwo typu.
Budowniczy
Użyj tego
źródło
Collection
(w tym przypadku aArrayList
) jest wymuszany na dzwoniącym, podczas gdy mogą wiedzieć, że aLinkedList
jest bardziej odpowiedni, lub sama niezmienna tablica (taka jak varargs z pytania OP). W przypadku zastosowania nie wyspecjalizowanego może to być właściwe, ale wystarczy wskazać, że jest to również ograniczenie, w pewnym sensie, w zależności od kodu otaczającego to i twoich potrzeb.Jawne rzutowanie parametrów na Object w wywołaniu metody vararg sprawi, że kompilator będzie zadowolony bez uciekania się do @SuppressWarnings.
Uważam, że problem polega na tym, że kompilator musi dowiedzieć się, jaki konkretny typ tablicy ma utworzyć. Jeśli metoda nie jest ogólna, kompilator może użyć informacji o typie z metody. Jeśli metoda jest ogólna, próbuje ustalić typ tablicy na podstawie parametrów użytych podczas wywołania. Jeśli typy parametrów są jednorodne, zadanie to jest łatwe. Jeśli się różnią, kompilator stara się moim zdaniem być zbyt sprytny i tworzy ogólną tablicę typu unii. Wtedy czuje potrzebę ostrzeżenia cię przed tym. Prostszym rozwiązaniem byłoby utworzenie Object [], gdy nie można lepiej zawęzić typu. Powyższe rozwiązanie właśnie to wymusza.
Aby lepiej to zrozumieć, baw się z wywołaniami powyższej metody list w porównaniu z następującą metodą list2.
źródło
Możesz dodać @SafeVarargs do metody od wersji Java 7 i nie musisz dodawać adnotacji do kodu klienta.
źródło
Możesz przeładować metody. To nie rozwiązuje problemu, ale minimalizuje liczbę ostrzeżeń (i tak, to hack!)
źródło
Jest to bardzo łatwy problem do rozwiązania: użyj
List<T>
!Należy unikać tablic typu referencyjnego.
W aktualnej wersji Javy (1.7) można oznaczyć metodę,
@SafeVargs
która usunie ostrzeżenie z wywołującego. Ostrożnie z tym jednak, a nadal lepiej bez starszych tablic.Zobacz także Ulepszone ostrzeżenia i błędy kompilatora podczas używania nierefikowalnych parametrów formalnych z uwagą techniczną Varargs Methods .
źródło
Podczas pracy z tablicami typu ogólnego jestem zmuszony przekazać odwołanie do typu ogólnego. Dzięki temu mogę faktycznie wykonać kod ogólny, używając java.lang.reflect.Array.
http://java.sun.com/javase/6/docs/api/java/lang/reflect/Array.html
źródło