2009-03-11 31 views
6

Me gustaría implementar un método que toma un Object como argumento, lo arroja a un tipo arbitrario, y si eso falla, devuelve null. Esto es lo que tengo hasta ahora:Java generics

public static void main(String[] args) { 
    MyClass a, b; 
    a = Main.<MyClass>staticCast(new String("B")); 
} 

public static class MyClass { 
} 

public static <T> T staticCast(Object arg) { 
    try { 
     if (arg == null) return null; 
     T result = (T) arg; 
     return result; 
    } catch (Throwable e) { 
     return null; 
    } 
} 

Por desgracia, la excepción de difusión clase no es lanzada/atrapado en el cuerpo de la función staticCast(). Parece que el compilador de Java genera la función String staticCast(Object arg) en la que tiene una línea String result = (String) arg; aunque explícitamente digo que el tipo de plantilla debe ser MyClass. ¿Alguna ayuda? Gracias.

+0

Por cierto, usted debería estar atrapando g solo ClassCastException, no Throwable. La captura de Throwable puede causar serios problemas. –

Respuesta

10

Dado que la información de tipo genérico se borra en tiempo de ejecución, la forma estándar para echar a un tipo genérico es con un objeto Class:

public static <T> T staticCast(Object arg, Class<T> clazz) { 
    if (arg == null) return null; 
    if (!clazz.isInstance(arg)) 
     return null; 
    T result = clazz.cast(arg); 
    return result; 
} 

A continuación, llame así:

a = Main.staticCast("B", MyClass.class); 
+0

usando Class.isInstance sería más directo. –

+0

hmm, clazz? ¿Es eso como un klass? –

+0

isInstance solo funcionará si el objeto es una instancia de clazz, no si se trata de una subclase de clazz. isAssignableFrom funcionará en cualquier elemento que se pueda convertir en clazz, incluso en subclases. –

6

No puede hacer lo que quiera ... al menos no de esta manera. El compilador eliminó toda la información, por lo que terminas con (T) como Objeto en el elenco, y eso funciona.

El problema es que más adelante está haciendo el objeto MyClass = (String); y eso no está permitido.

Ha omitido la comprobación de los compiladores y ha fallado en el tiempo de ejecución.

Entonces, ¿qué es exactamente lo que estás tratando de hacer? Si nos dice por qué quiere hacer esto, probablemente podamos decirle la forma Java de hacerlo.

Dada su comentario podría intentar algo como:

public class Main 
{ 
    public static void main(String[] args) 
    { 
     String a; 
     MyClass b; 
     a = staticCast(new String("B"), String.class); 
     b = staticCast(new String("B"), MyClass.class); 
     System.out.println(a); 
    } 

    public static class MyClass 
    { 
    } 

    public static <T> T staticCast(Object arg, final Class clazz) 
    { 
     // edit - oops forgot to deal with null... 
     if(arg == null) 
     { 
      return (null); 
     } 

     // the call to Class.cast, as mmeyer did, might be better... probably is better... 
     if(arg.getClass() != clazz) 
     { 
      // Given your answer to Ben S... 
      return (null); 

      // throw new ClassCastException("cannot cast a " + arg.getClass() + " to a " + clazz); 
     } 

     return ((T)arg); 
    } 
} 
+0

Veo, entonces T es un objeto en el reparto. Quiero un método separado para cada T que arroje el argumento a (T), y si eso falla, se captura una excepción y no se lanza.Según Paul Tomblin (debajo de la publicación) eso no va a suceder. – Budric

+0

el código que proporcioné en la edición debería hacer lo que quiera – TofuBeer

1

No se debe confundir genéricos de Java para las plantillas de C++. No sólo va a ser un método staticCast que se llama con diferentes borrado tipo, no uno para cada T.

No utilizar medicamentos genéricos en absoluto, me gustaría escribir de esta manera:

public static void main(String[] args) { 
    MyClass a, b; 
    a = (MyClass)Main.staticCast(new String("B"), MyClass.class); 
} 

public static class MyClass { 
} 

public static staticCast(Object arg, Class class) { 
     if (arg != null && class.isAssignableFrom(arg)) 
      return arg; 
     return null; 
} 

o el robo de otro contesta, el uso de los genéricos:

public static <T> T staticCast(Object arg, Class<T> class) { 
     if (arg != null && class.isAssignableFrom(arg)) 
     { 
      T result = class.cast(arg); 
      return result; 
     } 
     return null; 
} 
+0

Olvidé que CCE era una RuntimeException y no requería un bloque catch, o lo hubiera hecho como su segundo método originalmente. –

+0

¿Puede explicar por qué el compilador de Java no genera la función MyClass staticCast (Object arg); cuando especifico explícitamente el tipo T en la línea: a = Principal. staticCast (new String ("B")); Le dije explícitamente que ... Pensé Un enlace para leer un poco sería genial. – Budric

+0

@Budric: prueba http://java.sun.com/docs/books/tutorial/java/generics/erasure.html. Además, busque las preguntas etiquetadas [java] [generics]. Hay algunos bastante interesantes alrededor. –

4

¿Quieres decir como Class<T>.cast(Object obj)?

Algo así como:

Class.forName("YourClass").cast(obj); 

deberían hacer más o menos lo que quiere.

Tenga en cuenta que esto es bastante desagradable y es probable que sea un signo de diseño deficiente.

+0

Gracias. El problema es que arrojará una excepción de lanzamiento de clase si falla. Es idéntico al objeto del código: (YourClass) y se genera una excepción por error que debe verificar cada vez que utiliza esa línea de código. Me gustaría atrapar y esconder esa excepción dentro del método cast(). – Budric

+0

¿Deseas asSubclass o getConstructor(). NewInstance(). Cast? –

1

Estoy de acuerdo con Ben, sin embargo, prefiero la siguiente notación:

MyClass.class.cast(obj);