¿Qué es un cast sin marcar y cómo lo compruebo?


Creo que entiendo lo que significa el reparto sin comprobar (el reparto de uno a otro de un tipo diferente), pero ¿qué significa "Comprobar" el reparto? ¿Cómo puedo comprobar el molde para evitar esta advertencia en Eclipse?

Author: Whymarrh, 2010-04-22

3 answers

Unchecked cast significa que usted está (implícita o explícitamente) emitiendo de un tipo genérico a un tipo no calificado o al revés. Por ejemplo, esta línea

Set<String> set = new HashSet();

Producirá tal advertencia.

Por lo general, hay una buena razón para tales advertencias, por lo que debe tratar de mejorar su código en lugar de suprimir la advertencia. Cita de Effective Java, 2a Edición:

Elimina todas las advertencias sin marcar que puedas. Si eliminar todas las advertencias, que están seguros de que su código es typesafe, que es un muy qué bueno. Significa que no obtendrá un ClassCastException en tiempo de ejecución, y aumenta su confianza en que su programa se está comportando como usted pretendía.

Si no se puede eliminar una advertencia, y se puede demostrar que el código que provocado la advertencia es typesafe, entonces (y solo entonces) suprimir la advertencia con una anotación @SuppressWarnings("unchecked"). Si suprime las advertencias sin probar primero que el código es typesafe, solo te estás dando a ti mismo un falsa sensación de seguridad. El código puede compilar sin emitir ninguna advertencia, pero todavía puede lanzar un ClassCastException en tiempo de ejecución. Si, sin embargo, ignoras advertencias sin marcar que sabe que es seguro (en lugar de suprimirlas), usted no notará cuando aparezca una nueva advertencia que represente un problema real. El una nueva advertencia se perderá entre todas las falsas alarmas que no silenciaste.

Por supuesto, no siempre es tan fácil eliminar las advertencias como con el código anterior. Sin sin embargo, al ver su código, no hay manera de saber cómo hacerlo seguro.

 32
Author: Péter Török,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-22 18:04:11

Para elaborar más sobre lo que Pedro escribió:

Los casts de tipos no genéricos a tipos genéricos pueden funcionar bien en tiempo de ejecución, porque los parámetros genéricos se borran durante la compilación, por lo que nos queda un cast legítimo. Sin embargo, el código puede fallar más tarde con una inesperada ClassCastException debido a una suposición incorrecta con respecto al parámetro type. Por ejemplo:

List l1 = new ArrayList();
l1.add(33);
ArrayList<String> l2 = (ArrayList<String>) l1;
String s = l2.get(0);

La advertencia sin marcar en la línea 3 indica que el compilador no puede garantizar la seguridad del tipo más, en el sentido de que una inesperada ClassCastException puede ocurrir más tarde. Y esto sucede en la línea 4, que realiza un molde implícito.

 42
Author: Eyal Schneider,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-22 18:12:09

Un cast sin marcar, a diferencia de cast marcado, no comprueba la seguridad de tipo en tiempo de ejecución.

Aquí hay un ejemplo basado en la sección Consider typesafe heterogenous containers de la 3a ed. de "Effective Java" por Joshua Bloch, pero la clase container se rompe intencionalmente - almacena y devuelve el tipo incorrecto:

public class Test {

    private static class BrokenGenericContainer{
        private final Map<Class<?>, Object> map= new HashMap<>();

        public <T> void store(Class<T> key, T value){
            map.put(key, "broken!"); // should've been [value] here instead of "broken!"
        }

        public <T> T retrieve(Class<T> key){
//          return key.cast(map.get(key)); // a checked cast 
            return (T)map.get(key);        // an unchecked cast
        }

    }

    public static void main(String[] args) {
        BrokenGenericContainer c= new BrokenGenericContainer();
        c.store(Integer.class, 42);
        List<Integer> ints = new ArrayList<>();
        ints.add(c.retrieve(Integer.class));
        Integer i = ints.get(0);
    }

}


Si el retrieve() utiliza un fundido sin marcar -(T)map.get(key) - ejecutar este programa llevará a ClassCastException que ocurra en la línea Integer i = ints.get(0). El método retrieve() se completará porque el tipo real no se comprobó en tiempo de ejecución:

Exception in thread "main" 
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at Test.main(Test.java:27)


Pero si el retrieve() utiliza un marcado cast - key.cast(map.get(key)) - ejecutar este programa llevará a ClassCastException que ocurra en la línea key.cast(map.get(key)), porque el cast marcado descubrirá que el tipo es incorrecto y lanzará la excepción. El método retrieve() no se completará:

Exception in thread "main" java.lang.ClassCastException: 
                                          Cannot cast java.lang.String to java.lang.Integer
    at java.lang.Class.cast(Class.java:3369)
    at Test$BrokenGenericContainer.retrieve(Test.java:16)
    at Test.main(Test.java:26)

Puede parecer poca diferencia, pero en el caso del reparto sin control, a String se abrió camino con éxito en a List<Integer>. En aplicaciones del mundo real, consecuencias de esto puede ser... bueno, severo. En caso de que el molde marcado, el desajuste de tipo se descubrió lo antes posible.


Para evitar la advertencia de casts sin marcar, se puede usar @SuppressWarnings("unchecked"), si el programador está realmente seguro de que el método es seguro. La mejor alternativa es usar genéricos y yesos revisados cuando sea posible.

Como Joshua Bloch lo puso, {[18]]}

...las advertencias sin marcar son importantes. No los ignores.


En aras de la exhaustividad, esta respuesta trata de los detalles del Eclipse.

 0
Author: jihor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-12 21:24:27