Genéricos: Compilador parece incapaz de reconocer que el tipo pasado de un argumento es el mismo que lo que se devuelve - ¿por qué?

StackOverflow https://stackoverflow.com/questions/3120428

  •  30-09-2019
  •  | 
  •  

Pregunta

Digamos que tengo varios POJOs la que todos se extienden un supertipo común, BaseObject.

Tengo un GenericDao que se declara como public interface GenericDao<T>.

Para cada DAO específica del tipo, tengo una interfaz que se extiende el tipo genérico y la restringe a un tipo concreto (public interface UserDao extends GenericDao<User>) y luego una implementación de la DAO-tipo específico.

En una clase que los intentos de utilizar una serie de implementaciones GenericDao, tengo un método que se parece a

public <T extends BaseObject> long create(T object) {
    return getDao(object.getClass()).save(object);
}

Si implemento getDao() para que de parámetro es un objeto Class, como

private <T extends BaseObject> GenericDao<T> getDao(Class<T> clazz) { ... }

A continuación, la llamada a getDao(object.getClass() en el método create() falla al compilar - el compilador parece interpretar el tipo de retorno de getDao() como

GenericDao<? extends BaseContractObject>

en lugar de reconocer que getDao(Class<T>) me va a devolver un GenericDao del mismo tipo T.

Puede alguien explicar por qué esto es? Entiendo que repetidas apariciones del mismo tipo unido o Comodín No es necesario hacer referencia al mismo tipo; Sin embargo parece que el compilador debe reconocer a partir de la firma de getDao(Class<T>) que el T aprobada en la misma debe ser devuelto T (pero obviamente no es capaz de reconocer esto, el ¿Por qué es la parte fallo para comprender).

Si en cambio defino la firma de getDao ser

private <T extends BaseContractObject> GenericDao<T> getDao(T obj) { ... }

A continuación, no hay ningún problema en la compilación de una aplicación create() que se parece a

public <T extends BaseContractObject> long create(T object) {
    return getDao(object).save(object);
}

¿Por qué es el compilador capaz de reconocer en este caso que el argumento T pasado a getDao(T) es el mismo T en el tipo de retorno, mientras que no podía reconocer esto cuando el argumento era Class<T>?

¿Fue útil?

Solución

El object.getClass() expresión, donde objeto es de tipo T extends BaseObject, devuelve un Class<? extends BaseObject>, no un Class<T> como uno podría esperar. Así, getDao() devuelve un DAO del mismo tipo que recibe; sólo que no está recibiendo el tipo esperado.

Otros consejos

Este es un tema clásico de tipo borrado. getClass() tiene la firma siguiente:

public final native Class<? extends Object> getClass();

Si usted tiene un String y hacer un getClass() en él, la clase que se obtiene es Class<? extends String>. Los javadocs leen:

 * @return The <code>java.lang.Class</code> object that represents
 *         the runtime class of the object.  The result is of type
 *         {@code Class<? extends X>} where X is the
 *         erasure of the static type of the expression on which
 *         <code>getClass</code> is called.

tendrá que forzar la siguiente conversión al conseguir que funcione:

@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>)object.getClass();
return getDao(clazz).save(object);

que funciona para mí.

Creo que esto debería explicar por qué la restricción no está haciendo lo que se espera:

http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeParameters .html # FAQ206

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top