Generics: Compiler scheint nicht in der Lage zu erkennen, dass der Typ auf ein Argument übergeben ist das gleiche wie das, was zurückgegeben wird - warum?
-
30-09-2019 - |
Frage
Lassen Sie uns sagen, dass ich mehrere POJOs haben, die alle einen gemeinsamen Supertyp erweitern, BaseObject
.
Ich habe eine GenericDao
, die als public interface GenericDao<T>
deklariert wird.
Für jede typspezifische DAO, habe ich eine Schnittstelle, die die generische Art und engt sie auf einen konkreten Typ (public interface UserDao extends GenericDao<User>
) und dann eine Implementierung der typspezifischen DAO erstreckt.
In einer Klasse, die versucht, eine Reihe von GenericDao
Implementierungen zu verwenden, ich habe eine Methode, das aussieht wie
public <T extends BaseObject> long create(T object) {
return getDao(object.getClass()).save(object);
}
Wenn ich getDao()
implementieren, so dass es den Parameter ist ein Class
Objekt, wie
private <T extends BaseObject> GenericDao<T> getDao(Class<T> clazz) { ... }
Dann wird der Anruf an getDao(object.getClass()
in der create()
Methode schlägt fehl, zu kompilieren - der Compiler erscheint den Rückgabetyp von getDao()
als
GenericDao<? extends BaseContractObject>
anstatt dass getDao(Class<T>)
erkennen wird mir eine GenericDao
des gleichen Typs T
zurückzukehren.
erklären kann jemand, warum dies? Ich verstehe, dass wiederholtes Auftreten des gleichen Typs gebunden oder Wildcard nicht notwendig auf die gleiche Art beziehen; aber es ist wie der Compiler scheint aus der Signatur von getDao(Class<T>)
sollte erkennen, dass die T übergeben sollte gleich T sein zurückgegeben (aber offensichtlich ist es nicht in der Lage, dies zu erkennen, die Warum ist der Teil I scheitern zu erfassen).
Wenn ich stattdessen getDao
Unterschrift definieren sein
private <T extends BaseContractObject> GenericDao<T> getDao(T obj) { ... }
Dann gibt es kein Problem eine create()
Implementierung bei der Zusammenstellung, die wie
public <T extends BaseContractObject> long create(T object) {
return getDao(object).save(object);
}
Warum ist der Compiler der Lage, in diesem Fall erkennen, dass das T
Argument getDao(T)
geben wird, ist der gleiche T
in dem Rückgabetyp, während sie das nicht erkennen konnte, wenn das Argument Class<T>
ist?
Lösung
Der Ausdruck object.getClass()
, wo Objekte vom Typ T extends BaseObject
sind, gibt ein Class<? extends BaseObject>
, kein Class<T>
wie man erwarten könnte. So wird getDao()
eine DAO des gleichen Typs zurückkehr es empfängt; es ist einfach nicht den erwarteten Typ zu empfangen.
Andere Tipps
Dies ist eine klassische Typ Löschung Ausgabe. getClass()
hat die folgende Signatur:
public final native Class<? extends Object> getClass();
Wenn Sie eine String
haben und machen einen getClass()
darauf, die Klasse, die Sie erhalten, ist Class<? extends String>
. Die javadocs lesen:
* @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.
Sie müssen die folgende Besetzung zwingen, es zu Arbeit zu bekommen:
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>)object.getClass();
return getDao(clazz).save(object);
Das funktioniert für mich.
ich denke, das sollte erklären, warum die Einschränkung nicht tut, was Sie erwarten:
http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeParameters .html # FAQ206