Rozumiem, że dzieje się tak w przypadku Java 7, gdy używa się varargs z typem ogólnym;
Ale moje pytanie brzmi ...
Co dokładnie oznacza Eclipse, gdy mówi „jego użycie może potencjalnie zanieczyścić stertę?”
I
W jaki sposób nowa @SafeVarargs
adnotacja temu zapobiega?
java
eclipse
generics
variadic-functions
hertzsprung
źródło
źródło
Possible heap pollution from parameterized vararg type
Odpowiedzi:
Zanieczyszczenie hałd to termin techniczny. Odnosi się do odwołań, których typ nie jest nadtypem obiektu, na który wskazują.
Może to prowadzić do „niewyjaśnienia”
ClassCastException
.@SafeVarargs
wcale tego nie zapobiega. Istnieją jednak metody, które prawdopodobnie nie zanieczyszczą sterty, kompilator po prostu nie może tego udowodnić. Wcześniej osoby wywołujące takie interfejsy API otrzymywały irytujące ostrzeżenia, które były całkowicie bezcelowe, ale musiały być tłumione na każdej stronie połączeń. Teraz autor interfejsu API może usunąć go raz w witrynie deklaracji.Jednak jeśli metoda faktycznie nie jest bezpieczna, użytkownicy nie będą już ostrzegani.
źródło
Kiedy deklarujesz
public static <T> void foo(List<T>... bar)
kompilator konwertuje go napublic static <T> void foo(List<T>[] bar)
następnie dopublic static void foo(List[] bar)
Powstaje wówczas niebezpieczeństwo, że przez pomyłkę przypiszesz niepoprawne wartości do listy, a kompilator nie spowoduje błędu. Na przykład, jeśli
T
jest a,String
to następujący kod zostanie skompilowany bez błędów, ale zakończy się niepowodzeniem w czasie wykonywania:Jeśli sprawdziłeś metodę, aby upewnić się, że nie zawiera ona takich luk, możesz ją opatrzyć adnotacjami,
@SafeVarargs
aby ukryć ostrzeżenie. W przypadku interfejsów użyj@SuppressWarnings("unchecked")
.Jeśli pojawi się ten komunikat o błędzie:
i masz pewność, że korzystanie z niego jest bezpieczne, powinieneś użyć
@SuppressWarnings("varargs")
zamiast tego. Zobacz Czy @SafeVarargs jest odpowiednią adnotacją dla tej metody? i https://stackoverflow.com/a/14252221/14731, aby uzyskać miłe wyjaśnienie tego drugiego rodzaju błędu.Bibliografia:
źródło
Object[]
. Tak długo, jak nie rzucaszObject[]
, wygląda na to, że powinieneś być w porządku.static <T> void bar(T...args) { ((Object[])args)[0] = "a"; }
. A potem zadzwońbar(Arrays.asList(1,2));
.Object[]
pytanie, dlaczego kompilator uruchomiłby ostrzeżenie, jeśli nie? W końcu powinno to być dość łatwe do sprawdzenia w czasie kompilacji (w przypadku, gdy nie przekażę go innej funkcji o podobnej sygnaturze, w takim przypadku druga funkcja powinna wywołać ostrzeżenie). Nie wierzę, że to naprawdę jest sedno ostrzeżenia („Jesteś bezpieczny, jeśli nie rzucisz”) i nadal nie rozumiem, w którym przypadku mam się dobrze.bar(Integer...args)
.). Jaki jest więc sens tego ostrzeżenia?@SafeVarargs
nie zapobiega temu, jednak nakazuje, aby kompilator był bardziej rygorystyczny podczas kompilowania kodu, który go używa.http://docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs.html wyjaśnia to bardziej szczegółowo.
Zanieczyszczenie sterty występuje wtedy,
ClassCastException
gdy wykonujesz operację na interfejsie ogólnym i zawiera on inny typ niż zadeklarowany.źródło
Gdy używasz varargs, może to spowodować utworzenie
Object[]
argumentu do przechowywania argumentów.Dzięki analizie ucieczki JIT może zoptymalizować tworzenie tablicy. (Jeden z niewielu razy to stwierdziłem). Nie gwarantuje się, że zostanie zoptymalizowany, ale nie martwiłbym się tym, dopóki nie zobaczysz problemu w twoim profilu pamięci.
AFAIK
@SafeVarargs
pomija kompilator i nie zmienia zachowania JIT.źródło
@SafeVarargs
.Powodem jest to, że varargs dają możliwość wywoływania z nieparametryzowaną tablicą obiektów. Więc jeśli twój typ to List <A> ..., można go również wywołać z List [] bez typu varargs.
Oto przykład:
Jak widać List [] b może zawierać dowolnego rodzaju konsumenta, a jednak ten kod się kompiluje. Jeśli używasz varargs, wszystko jest w porządku, ale jeśli użyjesz definicji metody po usunięciu typu - void test (List []) - kompilator nie sprawdzi typów parametrów szablonu. @SafeVarargs usunie to ostrzeżenie.
źródło