java kotlin - Posible contaminación del montón a través del parámetro varargs





argumentos variables (6)


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.

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 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.




Su comprensión es ligeramente defectuosa. El operador de diamante es una buena característica ya que no tienes que repetirte. Tiene sentido definir el tipo una vez cuando declara el tipo, pero simplemente no tiene sentido definirlo de nuevo en el lado derecho. El principio DRY.

Ahora para explicar todo el fuzz sobre la definición de tipos. Tiene razón en que el tipo se elimine en el tiempo de ejecución, pero una vez que quiera recuperar algo de una Lista con definición de tipo, lo recupera como el tipo que definió al declarar la lista; de lo contrario, perdería todas las características específicas y tendría solo el Las características del objeto, excepto cuando se convierte el objeto recuperado a su tipo original, que a veces puede ser muy difícil y dar lugar a una excepción ClassCastException.

Usando List<String> list = new LinkedList() obtendrá advertencias de tipo de letra.





java eclipse generics variadic-functions