ジェネリック:コンパイラは、引数に渡された型が返された型と同じであることを認識できないようです。なぜですか?
-
30-09-2019 - |
質問
共通のスーパータイプを拡張するいくつかの POJO があるとします。 BaseObject
.
私は持っています GenericDao
これは次のように宣言されています public interface GenericDao<T>
.
型固有の DAO ごとに、ジェネリック型を拡張し、それを具象型に制限するインターフェイスがあります (public interface UserDao extends GenericDao<User>
)、次に型固有の DAO の実装です。
いくつかのクラスを使用しようとするクラスでは、 GenericDao
実装では、次のようなメソッドがあります
public <T extends BaseObject> long create(T object) {
return getDao(object.getClass()).save(object);
}
私が実装したら getDao()
そのパラメータは Class
オブジェクトなど
private <T extends BaseObject> GenericDao<T> getDao(Class<T> clazz) { ... }
次に、への呼び出し getDao(object.getClass()
の中に create()
メソッドのコンパイルに失敗します - コンパイラは戻り値の型を解釈しているようです getDao()
として
GenericDao<? extends BaseContractObject>
それを認識するのではなく getDao(Class<T>)
を返してくれる GenericDao
同じ種類の T
.
誰かがこれがなぜなのか説明できますか?同じ型バインドまたはワイルドカードが繰り返し出現する場合、必ずしも同じ型を参照する必要はないことを理解しています。ただし、コンパイラは署名から認識する必要があるようです getDao(Class<T>)
渡される T は返される T と同じである必要があります (ただし、明らかにこれを認識できません。 なぜ それは私が理解できていない部分です)。
代わりに定義すると getDao
の署名は
private <T extends BaseContractObject> GenericDao<T> getDao(T obj) { ... }
そうすれば、コンパイルに問題はありません create()
次のような実装
public <T extends BaseContractObject> long create(T object) {
return getDao(object).save(object);
}
では、この場合、コンパイラはなぜ次のことを認識できるのでしょうか。 T
に渡される引数 getDao(T)
同じです T
戻り値の型では、引数が次の場合にはこれを認識できませんでした。 Class<T>
?
解決
表現 object.getClass()
, 、オブジェクトのタイプは次のとおりです。 T extends BaseObject
, 、を返します Class<? extends BaseObject>
, ではありません Class<T>
ご想像のとおり。それで、 getDao()
受け取ったものと同じタイプの DAO を返します。期待された型を受け取っていないだけです。
他のヒント
これは古典的なタイプの消去の問題です。 getClass()
次の署名があります。
public final native Class<? extends Object> getClass();
あなたが持っている場合 String
とします getClass()
その上、あなたが得るクラスはそうです Class<? extends String>
. 。 Javadocsは読みました:
* @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.
次のキャストを強制して機能させる必要があります。
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>)object.getClass();
return getDao(clazz).save(object);
それは私のために働きます。
これは、制約があなたが期待していることをしていない理由を説明するべきだと思います:
http://www.angelikalanger.com/genericsfaq/faqsections/typeparameters.html#faq206