Génériques: compilateur semble incapable de reconnaître que le type est passé à un argument est le même que ce qui est retourné - pourquoi?

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

  •  30-09-2019
  •  | 
  •  

Question

Disons que j'ai plusieurs POJO qui se prolongent tout une commune supertype, BaseObject.

J'ai un GenericDao qui est déclarée comme public interface GenericDao<T>.

Pour chaque DAO spécifique de type, j'ai une interface qui étend le type générique et le limite à un type de béton (public interface UserDao extends GenericDao<User>), puis une mise en oeuvre du DAO type spécifique.

Dans une classe qui tente d'utiliser un certain nombre d'implémentations de GenericDao, j'ai une méthode qui ressemble à

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

Si je mets en œuvre getDao() de telle sorte que le paramètre de c'est un objet Class, comme

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

Alors l'appel à getDao(object.getClass() dans la méthode create() ne peut pas compiler - le compilateur semble interpréter le type de retour de getDao() comme

GenericDao<? extends BaseContractObject>

au lieu de reconnaître que getDao(Class<T>) va me retourner un GenericDao du même type T.

Quelqu'un peut-il expliquer pourquoi il en est? Je comprends que les apparences répétées du même type lié ou caractère générique ne correspondent pas nécessairement se référer au même type; mais il semble que le compilateur doit reconnaître à partir de la signature de getDao(Class<T>) que le T adoptée en devrait être le même T retourné (mais évidemment il n'est pas capable de reconnaître cela, le pourquoi est la partie je ne à saisir).

Si je définis au lieu de la signature getDao être

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

Alors il n'y a pas de problème dans la compilation d'une mise en œuvre de create() qui ressemble à

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

Alors, pourquoi le compilateur capable de reconnaître dans ce cas que l'argument de T passé à getDao(T) est le même T dans le type de retour, alors qu'il ne pouvait pas reconnaître quand l'argument était Class<T>?

Était-ce utile?

La solution

Le object.getClass() d'expression, où l'objet est de type T extends BaseObject, retourne un Class<? extends BaseObject>, pas Class<T> comme on pouvait s'y attendre. Ainsi, getDao() renvoie une OAC du même type qu'il reçoit; il est tout simplement pas recevoir le type attendu.

Autres conseils

Ceci est un problème d'effacement de type classique. getClass() a la signature suivante:

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

Si vous avez un String et faire une getClass() là-dessus, la classe que vous obtenez est Class<? extends String>. Les javadocs lire:

 * @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.

Vous aurez besoin de forcer la distribution suivante pour l'obtenir au travail:

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

qui fonctionne pour moi.

Je pense que cela devrait expliquer pourquoi la contrainte ne fait pas ce que vous attendez:

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top