Contaminación de montón potencial a través del parámetro varargs

Entiendo que esto ocurre con Java 7 cuando se usan varargs con un tipo genérico;

Pero mi pregunta es …

¿Qué quiere decir exactamente Eclipse cuando dice que “su uso podría potencialmente contaminar el montón”?

Y

¿Cómo es que la nueva anotación @SafeVarargs evita esto?

La contaminación de montón es un término técnico. Se refiere a referencias que tienen un tipo que no es un supertipo del objeto al que apuntan.

 List listOfAs = new ArrayList<>(); List listOfBs = (List)(Object)listOfAs; // points to a list of As 

Esto puede llevar a ClassCastException s “inexplicables”.

 // if the heap never gets polluted, this should never throw a CCE B b = listOfBs.get(0); 

@SafeVarargs no evita esto en absoluto. Sin embargo, hay métodos que probablemente no contaminarán el montón, el comstackdor simplemente no puede probarlo. Anteriormente, las personas que llamaban a dichas API recibían advertencias molestas que eran completamente inútiles, pero tenían que suprimirse en cada sitio de llamadas. Ahora el autor de la API puede suprimirlo una vez en el sitio de statement.

Sin embargo, si el método en realidad no es seguro, los usuarios ya no serán advertidos.

Cuando declaras

public static void foo(List... bar) el comstackdor lo convierte en

public static void foo(List[] bar) luego a

public static void foo(List[] bar)

Entonces surge el peligro de que asigne erróneamente valores incorrectos a la lista y el comstackdor no active ningún error. Por ejemplo, si T es una String , el siguiente código se comstackrá sin error pero fallará en el tiempo de ejecución:

 // First, strip away the array type (arrays allow this kind of upcasting) Object[] objectArray = bar; // Next, insert an element with an incorrect type into the array objectArray[0] = Arrays.asList(new Integer(42)); // Finally, try accessing the original array. A runtime error will occur // (ClassCastException due to a casting from Integer to String) T firstElement = bar[0].get(0); 

Si revisó el método para asegurarse de que no contiene tales vulnerabilidades, puede anotarlo con @SafeVarargs para suprimir la advertencia. Para las interfaces, use @SuppressWarnings("unchecked") .

Si obtiene este mensaje de error:

El método de Varargs podría causar contaminación acumulativa del parámetro varargs no reificable

y está seguro de que su uso es seguro, debería usar @SuppressWarnings("varargs") lugar. Consulte ¿Es @SafeVarargs una anotación adecuada para este método? y https://stackoverflow.com/a/14252221/14731 para una buena explicación de este segundo tipo de error.

Referencias

@SafeVarargs no evita que suceda, sin embargo, exige que el comstackdor sea más estricto al comstackr el código que lo usa.

http://docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs.html explica esto con más detalle.

La contaminación de montón ocurre cuando obtienes una ClassCastException cuando realizas una operación en una interfaz genérica y contiene otro tipo distinto de declarado.

Cuando utiliza varargs, puede dar como resultado la creación de un Object[] para contener los argumentos.

Debido al análisis de escape, el JIT puede optimizar esta creación de matriz. (Una de las pocas veces que he encontrado que lo hace) No está garantizado que se optimice, pero no me preocuparía a menos que veas que es un problema en tu perfil de memoria.

AFAIK @SafeVarargs suprime una advertencia del comstackdor y no cambia el comportamiento del JIT.

La razón es porque los varargs dan la opción de ser llamados con una matriz de objetos no parametrizada. Entonces, si su tipo era List …, también se puede llamar con el tipo List [] non-varargs.

Aquí hay un ejemplo:

 public static void testCode(){ List[] b = new List[1]; test(b); } @SafeVarargs public static void test(List... a){ } 

Como puede ver, List [] b puede contener cualquier tipo de consumidor y, sin embargo, este código se comstack. Si usa varargs, está bien, pero si utiliza la definición del método después de la eliminación de tipo – prueba de vacío (Lista []) – entonces el comstackdor no verificará los tipos de parámetros de la plantilla. @SafeVarargs suprimirá esta advertencia.