java - argumentos - Posible contaminación del montón a través del parámetro varargs
vararg kotlin (5)
Entiendo que esto ocurre con Java 7 cuando se usan varargs con un tipo genérico;
Pero mi pregunta es ...
¿Qué significa exactamente Eclipse cuando dice "su uso podría contaminar el montón?"
Y
¿Cómo previene esto la nueva anotación @SafeVarargs
?
Cuando usa varargs, puede resultar en la creación de un Object[]
para mantener los argumentos.
Debido al análisis de escape, el JIT puede optimizar esta creación de matriz. (Una de las pocas veces que lo encontré lo hace) No se garantiza que se optimice, pero no me preocuparía por ello a menos que vea que es un problema en su perfil de memoria.
AFAIK @SafeVarargs
suprime una advertencia del compilador y no cambia el comportamiento del JIT.
Cuando usted declara
public static <T> void foo(List<T>... bar)
el compilador lo convierte a
public static <T> void foo(List<T>[] bar)
luego a
public static <T> void foo(List[] bar)
Entonces surge el peligro de que erróneamente asigne valores incorrectos a la lista y el compilador no generará ningún error. Por ejemplo, si T
es una String
, el siguiente código se compilará sin error pero fallará en 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 contenga tales vulnerabilidades, puede anotarlo con @SafeVarargs
para suprimir la advertencia. Para interfaces, utilice @SuppressWarnings("unchecked")
.
Si recibe este mensaje de error:
El método de Varargs podría causar la contaminación del montón de un parámetro de Varargs no reificable
y está seguro de que su uso es seguro, entonces debería usar @SuppressWarnings("varargs")
lugar. Ver ¿Es @SafeVarargs una anotación apropiada para este método? y https://.com/a/14252221/14731 para una buena explicación de este segundo tipo de error.
Referencias:
La contaminación del 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<A> listOfAs = new ArrayList<>();
List<B> listOfBs = (List<B>)(Object)listOfAs; // points to a list of As
Esto puede llevar a s ClassCastException
"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 compilador simplemente no puede probarlo. Anteriormente, las personas que llamaban a tales APIs recibían advertencias molestas que eran completamente inútiles, pero tenían que ser suprimidas en cada sitio de llamada. Ahora el autor de la API puede suprimirlo una vez en el sitio de declaración.
Sin embargo, si el método en realidad no es seguro, los usuarios ya no serán advertidos.
La razón es porque varargs da la opción de ser llamado con una matriz de objetos no parametrizados. Por lo tanto, si su tipo era Lista <A> ..., también se puede llamar con el tipo no varargs Lista [].
Aquí hay un ejemplo:
public static void testCode(){
List[] b = new List[1];
test(b);
}
@SafeVarargs
public static void test(List<A>... a){
}
Como puede ver, la Lista [] b puede contener cualquier tipo de consumidor y, sin embargo, este código se compila. Si usa varargs, entonces está bien, pero si usa la definición de método después del borrado de tipo - prueba de anulación (Lista []) - el compilador no verificará los tipos de parámetros de la plantilla. @SafeVarargs suprimirá esta advertencia.
@SafeVarargs
no evita que esto suceda, sin embargo, exige que el compilador sea más estricto al compilar el código que lo usa.
http://docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs.html explica esto con mayor detalle.
La contaminación del montón se produce cuando se obtiene una ClassCastException
al realizar una operación en una interfaz genérica y contiene un tipo diferente al declarado.