2012-05-23 16 views
6

Creo una clase de Preferencias y para los Getters quiero utilizar el Token de tipo Runtime.Obtiene la instancia de la clase <T> [Token de tipo de tiempo de ejecución]

Así que aquí es mi método de obtención:

public <T> T get(String key, Class<T> clazz) { 
    // do some crazy stuff (e.g. Double <-> Float) 
} 

Hasta eso, todo funciona bien. Pero me gustaría que el parámetro de clase sea opcional.

boolean b = preferences.get(key); 

Así que añadir un método adicional:

public <T> T get(String key) { 
    // return get(key, Class<T>); 
} 

Ahora la pregunta: ¿Hay una manera de hacer eso? ¿Hay alguna forma de obtener una instancia/de Class<T>?

Es posible con una pequeña solución:

public <T> T get(String key, T... args) { 
    return get(key, (Class<T>) args.getClass().getComponentType()); 
} 

public <T> T get(String key, Class<T> clazz) { 
    System.out.println("key : " + key); 
    System.out.println("clazz: " + clazz); 
} 

// using 
Boolean b = get("mykey"); 

Respuesta

3

Es posible con una pequeña solución.

public <T> T get(String key, T... args) { 
    return get(key, (Class<T>) args.getClass().getComponentType()); 
} 

public <T> T get(String key, Class<T> clazz) { 
    System.out.println("key : " + key); 
    System.out.println("clazz: " + clazz); 
} 

// using 
Boolean b = get("mykey"); 

Jep No me gustan los varargs también, pero funciona hasta ahora.

+0

Trate de no copiar y pegar la misma respuesta a varias preguntas; si las preguntas son las mismas, considere marcarlas como duplicadas. He recuperado esta respuesta ya que eliminaste la otra. – BoltClock

+0

@BoltClock En realidad, accidentalmente publiqué mi respuesta en esa otra pregunta. Yo ** borré inmediatamente ** ese y lo publiqué aquí. Entonces mi respuesta nunca existe dos veces. [JFYI] –

+0

Ah, ya veo. Algunas veces el sistema se vuelve quisquilloso con las respuestas pegadas. ¡Gracias por aclararme! – BoltClock

3

No se puede. Pero si desea que el parámetro de clase sea opcional, simplemente pase null y verifique si no es nulo cuando lo usa.

Si quiere inferirlo desde el lado izquierdo, no es posible.

2

No. La información de tipo genérico se almacena en el método de llamada, el T get(String key) compilado solo sabe que es genérico pero no tiene forma de averiguar qué tipo de concreto se utilizó para llamarlo.

//code 
public <T> T get(String key) 
//calling code 
Integer value = get("value"); 

//once compiled 
public Object get(String key) 
//calling code 
Integer value = (Integer) get("value"); 
2

puede tener este tipo de código:

Integer i = getPref("integer"); 
System.out.println(i); 

@SuppressWarnings("unchecked") 
static <T> T getPref(String x) { 
    return (T)properties.get(x); 
} 

En este caso, el tipo de hecho <T> se infiere de la mano izquierda. Tenga en cuenta que esto solo ayuda a evitar un downcast explícito al Integer - para mí personalmente eso es suficiente y a menudo uso tales bestias. Otro punto a tener en cuenta es que la inferencia de tipos de Java es bastante coja y no podrás tener una llamada al getPref como argumento de otro método y tener el tipo de argumento inferido.

+0

¡De modo que las preferencias de la aplicación se convertirán en preferencias del sistema! Y no resuelve el problema. ¡No puedes convertir un entero en un doble! –

+1

@MarcelJaeschke ¿Qué importa si uso prefs del sistema como ejemplo? Es más claro que poner una variable no declarada 'preferencias' en el código. Y nada puede salvarte de una excepción de lanzamiento de clase si accedes al tipo de preferencia incorrecto. –

+0

Y cuando se produce un error al inferir, puede usar ' getPref (" foo ")' en lugar de hacer un método adicional para 'getPref (" foo ", Integer.class)' –

1

No se puede, pero ...

En lugar de sobrecargar a través de los genéricos, tenga en cuenta este patrón:

public boolean getBoolean(String key) { 
    // boolean impl here 
} 

public float getFloat(String key) { 
    // float impl here 
} 

// etc 

No sólo es más fácil de código, pero más fácil de usar también - por lo menos saber qué tipos son aceptables
Con su código actual, esto sería compilar:

SomeUnsupportedClass x = preferences.get("foo", SomeUnsupportedClass.class); 

pero sería explotar en tiempo de ejecución porque no se tiene código para apoyarlo.

Por cierto, eso es malo: desea detectar problemas en el tiempo de codificación, no en el tiempo de ejecución.

+0

Creo que getWhatever() es exactamente lo opuesto a lo que se menciona. BTW: cuando obtendrá un error si usa getBoolean (clave) {return (boolean) map.get (key)} y el valor es una cadena de caracteres? –

+1

En tiempo de ejecución, pero obtendrá una excepción de un tipo no coincidente sin importar el patrón de código que use. Pero cuando conoces el tipo, puedes hacer esto 'if (! (Value instanceof Boolean)) throw new IllegalArgumentException (" Value for '"+ key +' no es un booleano, pero es un" + value.getClass()) ; 'o similar a da más información, o simplemente devuelve' null' sin explotar si quieres. – Bohemian

+0

¿Por qué el voto a favor? – Bohemian

Cuestiones relacionadas