metodos - Genéricos de Java: Tipo genérico definido como solo tipo de devolución
metodos genericos java (6)
Estoy buscando un código GXT para GWT y me encontré con este uso de genéricos que no puedo encontrar otro ejemplo en los tutoriales de Java. El nombre de clase es com.extjs.gxt.ui.client.data.BaseModelData
si desea ver todo el código. Estas son las partes importantes:
private RpcMap map;
public <X> X get(String property) {
if (allowNestedValues && NestedModelUtil.isNestedProperty(property)) {
return (X)NestedModelUtil.getNestedValue(this, property);
}
return map == null ? null : (X) map.get(property);
}
X
se define en ningún otro lugar de la clase ni en ningún otro lugar de la jerarquía, y cuando pulso "ir a declaración" en eclipse, va a la <X>
en la firma del método público.
Intenté llamar a este método con los dos ejemplos siguientes para ver qué sucede:
public Date getExpiredate() {
return get("expiredate");
}
public String getSubject() {
return get("subject");
}
Compilan y no muestran errores o advertencias. Pensaría que al menos tendría que hacer un reparto para que esto funcione.
¿Significa esto que los genéricos permiten un valor de retorno mágico que puede ser cualquier cosa y que explotará en el tiempo de ejecución? Esto parece contrario a lo que se supone que deben hacer los genéricos. ¿Puede alguien explicarme esto y posiblemente darme un enlace a alguna documentación que lo explique un poco mejor? He revisado el PDF de Sun de 23 páginas sobre genéricos y cada ejemplo de valor de retorno se define a nivel de clase o en uno de los parámetros ingresados.
BaseModelData aumenta las advertencias no verificadas una vez compiladas, porque no es seguro. Usado de esta manera, su código lanzará una ClassCastException en tiempo de ejecución, aunque no tenga ninguna advertencia.
public String getExpireDate() {
return get("expiredate");
}
El método devuelve un tipo de lo que usted espera que sea ( <X>
está definido en el método y no tiene límites).
Esto es muy, muy peligroso ya que no se prevé que el tipo de retorno realmente coincida con el valor devuelto.
La única ventaja que esto tiene es que no tiene que emitir el valor de retorno de dichos métodos de búsqueda genéricos que pueden devolver cualquier tipo.
Yo diría: use tales constructos con cuidado, porque pierde casi todo tipo de seguridad y gana solo que no tiene que escribir un reparto explícito en cada llamada para get()
.
Y sí, esto es magia negra que explota en el tiempo de ejecución y rompe la idea de qué genéricos deberían lograr.
El tipo está declarado en el método. Eso es que " <X>
" significa. El tipo tiene un ámbito de solo el método y es relevante para una llamada en particular. El motivo por el que compila el código de prueba es que el compilador intenta determinar el tipo y se quejará solo si no puede. Hay casos en los que tienes que ser explícito.
Por ejemplo, la declaración para Collections.emptySet()
es
public static final <T> Set<T> emptySet()
En este caso, el compilador puede adivinar:
Set<String> s = Collections.emptySet();
Pero si no puede, debe escribir:
Collections.<String>emptySet();
Nota interesante, de RpcMap (GXT API 1.2)
encabezado de get:
public java.lang.Object get(java.lang.Object key)
Tener un parámetro genérico de <X>
allí que se haya desinstalado tiene el mismo efecto, excepto que no tiene que decir "Objeto" por todos lados. Estoy de acuerdo con el otro afiche, esto es descuidado y un poco peligroso.
Sí, esto es peligroso. Normalmente, protegerías este código así:
<X> getProperty(String name, Class<X> clazz) {
X foo = (X) whatever(name);
assert clazz.isAssignableFrom(foo);
return foo;
}
String getString(String name) {
return getProperty(name, String.class);
}
int getInt(String name) {
return getProperty(name, Integer.class);
}
Solo estaba tratando de descubrir lo mismo con una clase GXT. Específicamente, estaba tratando de llamar a un método con la firma de:
class Model {
public <X> X get(String property) { ... }
}
Para llamar al método anterior desde su código y hacer que emita X en una cadena, hago lo siguiente:
public String myMethod(Data data) {
Model model = new Model(data);
return model.<String>get("status");
}
El código anterior llamará al método get y le dirá que el tipo que devuelve X debe devolverse como una cadena.
En el caso donde el método está en la misma clase que usted, he encontrado que tengo que llamarlo con un "esto". Por ejemplo:
this.<String>get("status");
Como otros han dicho, esto es bastante descuidado y peligroso por parte del equipo de GXT.