Entendo que isso ocorra com o Java 7 ao usar varargs com um tipo genérico;
Mas minha pergunta é ..
O que exatamente o Eclipse quer dizer quando diz "seu uso pode poluir a pilha?"
E
Como a nova @SafeVarargs
anotação evita isso?
java
eclipse
generics
variadic-functions
hertzsprung
fonte
fonte
Possible heap pollution from parameterized vararg type
Respostas:
Poluição por pilha é um termo técnico. Refere-se a referências que possuem um tipo que não é um supertipo do objeto para o qual apontam.
Isso pode levar a "inexplicáveis"
ClassCastException
.@SafeVarargs
não impede isso. No entanto, existem métodos que provavelmente não poluirão a pilha, o compilador simplesmente não pode provar isso. Anteriormente, os chamadores dessas APIs recebiam avisos irritantes que eram completamente inúteis, mas precisavam ser suprimidos em todos os sites de chamadas. Agora, o autor da API pode suprimi-lo uma vez no site da declaração.No entanto, se o método realmente não for seguro, os usuários não serão mais avisados.
fonte
Quando você declara
public static <T> void foo(List<T>... bar)
o compilador o converte empublic static <T> void foo(List<T>[] bar)
então, parapublic static void foo(List[] bar)
Em seguida, surge o perigo de atribuir valores incorretos à lista por engano e o compilador não acionará nenhum erro. Por exemplo, se
T
for umString
, o código a seguir será compilado sem erros, mas falhará no tempo de execução:Se você revisou o método para garantir que ele não contenha tais vulnerabilidades, anote-o
@SafeVarargs
para suprimir o aviso. Para interfaces, use@SuppressWarnings("unchecked")
.Se você receber esta mensagem de erro:
e você tem certeza de que seu uso é seguro, você deve usá-lo
@SuppressWarnings("varargs")
. Consulte @SafeVarargs uma anotação apropriada para este método? e https://stackoverflow.com/a/14252221/14731 para obter uma boa explicação desse segundo tipo de erro.Referências:
fonte
Object[]
. Contanto que você não useObject[]
, parece que você deve ficar bem.static <T> void bar(T...args) { ((Object[])args)[0] = "a"; }
. E depois liguebar(Arrays.asList(1,2));
.Object[]
por que o compilador acionaria um aviso se não o fizesse? Afinal, deve ser bastante fácil verificar isso em tempo de compilação (no caso de eu não passá-lo para outra função com uma assinatura semelhante, caso em que a outra função deve acionar um aviso). Não acredito que esse seja realmente o cerne do aviso ("Você está seguro se não transmitir") e ainda não entendo;bar(Integer...args)
). Então, qual é o objetivo desse aviso?@SafeVarargs
não impede que isso aconteça, no entanto, exige que o compilador seja mais rígido ao compilar o código que o utiliza.http://docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs.html explica isso em mais detalhes.
Poluição de heap é quando você obtém um
ClassCastException
ao executar uma operação em uma interface genérica e ela contém outro tipo que não o declarado.fonte
Quando você usa varargs, isso pode resultar na criação de um
Object[]
para conter os argumentos.Devido à análise de escape, o JIT pode otimizar a criação desta matriz. (Uma das poucas vezes em que o encontrei) Não é garantido que ele seja otimizado, mas não me preocuparia com isso, a menos que você veja que isso é um problema no seu perfil de memória.
O AFAIK
@SafeVarargs
suprime um aviso do compilador e não altera o comportamento do JIT.fonte
@SafeVarargs
.O motivo é que os varargs oferecem a opção de serem chamados com uma matriz de objetos não parametrizada. Portanto, se o seu tipo era Lista <A> ..., ele também pode ser chamado com o tipo List [] não-varargs.
Aqui está um exemplo:
Como você pode ver, a Lista [] b pode conter qualquer tipo de consumidor e, mesmo assim, esse código é compilado. Se você usa varargs, está bem, mas se você usar a definição de método após o apagamento do tipo - teste nulo (Lista []) -, o compilador não verificará os tipos de parâmetro do modelo. @SafeVarargs suprimirá este aviso.
fonte