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?

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

  •  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

zu interpretieren
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

sieht
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?

War es hilfreich?

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

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top