2010-10-14 16 views
6

he implementado esta función:Java: Desactivada fundido de X a Y/cómo implementar castOrNull

static <X,Y> Y castOrNull(X obj) { 
    try { 
    return (Y)obj; 
    } 
    catch(ClassCastException e) { 
    return null; 
    } 
} 

Esto me da la advertencia del compilador:

Type safety: Unchecked cast from X to Y 

Qué no entiendo exactamente . ¿No es el try/catch que estoy haciendo aquí un cheque para ello? ¿Puedo ignorar la advertencia?

¿Funcionará mi función como se espera o no? ¿Cómo lo implementaría correctamente?

También probé con un cheque obj instanceof Y pero eso no funciona debido a la forma en que Java maneja los genéricos.

Por cierto, esta función me parece bastante útil (para hacer que otro código sea más limpio). Me pregunto si tal función ya puede existir en Java?


Un ejemplo donde yo quiero usarlo:

void removeEmptyRawStrings() { 
     for(Iterator<Entity> e = entities.iterator(); e.hasNext();) { 
      RawString s = castOrNull(e.next()); 
      if(s != null && s.content.isEmpty()) e.remove(); 
     } 
    } 

tengo casos como estos muy a menudo en mi código. Y creo que esto es más fácil de leer y más simple que cualquier otra cosa. Pero por favor dame una mejor sugerencia si tienes alguna información sobre cómo hacer que ese código sea aún más simple.

+0

Estaba pensando en esta advertencia hoy y si era posible tener un modelo verificado, pero no creo que puedas hacerlo. – DeliveryNinja

Respuesta

11

Por lo tanto, el problema aquí es que el parámetro genérico Y cuando se usa para fundición dinámica se trata como Object. Nunca lanzará un CCE. Obtiene un CCE arrojado en el llamando al método, ya que ha roto la seguridad del tipo estático.

también X es del todo inútil aquí:

Es casi seguro que la solución correcta es no intentar algo como esto. null es malo. Casting es malo.

Sin embargo, si usted está decidido a escribir sin sentido, se puede pasar el objeto Class:

public static <T> T evilMethod(Class<T> clazz, Object obj) { 
    try { 
     return clazz.cast(obj); 
    } catch (ClassCastException exc) { 
     return null; 
    } 
} 
+0

¡Ah, gran respuesta! – aioobe

+0

Gracias. Extendí mi pregunta para demostrar dónde/cómo quiero usarla. ¿Puedes describir por qué es malo hacer esto? ¿Y cómo puedo hacer que el código sea más simple sin usar esa función? – Albert

+5

¿Qué pasa con 'if (clazz.isInstance (obj)' en lugar de capturar CCE? –

1

Puede suprimir la advertencia en este método si conoce a ciencia cierta que no es un problema anotando con @SuppressWarnings("unchecked")

4

No estoy completamente seguro de que funcionará como se espera. (Depende de lo que se espera por supuesto :-) pero este código voluntad para el resultado instancia en un java.lang.ClassCastException (ideone):

public class Main { 

    public static void main(String[] args) { 
     Integer o = Main.<String, Integer>castOrNull("hello"); 
    } 


    public static <X, Y> Y castOrNull(X obj) { 
     try { 
      return (Y) obj; 
     } catch (ClassCastException e) { 
      return null; 
     } 
    } 
} 

@ Tom Hawtin consiguió the "correct" solution.

0

Gracias a los genéricos de Java manera en que diseñó este código no funcionará en absoluto. Los genéricos solo son útiles para verificar el tipo de tiempo de compilación ya que las clases no usan información de tipo genérico en tiempo de ejecución.

Su código será compilado a esto:

static Object castOrNull(Object obj) { 
    try { 
    return (Object)obj;//FAIL: this wont do anything 
    } 
    catch(ClassCastException e) { 
    return null; 
    } 
} 

El reparto de objeto nunca fallará, y el código compilado no tiene acceso a los tipos genéricos presentes en tiempo de compilación. Dado que el lanzamiento no ocurre de la forma en que debería recibir una advertencia para una operación no verificada.

+1

Comentario ligeramente erróneo en tu código;) – aioobe