このコードでは、型を として宣言できないのはなぜClass<? extends B>
ですか?
public class Foo<B> {
public void doSomething(B argument) {
Class<? extends Object> type = argument.getClass();
}
}
このコードでは、型を として宣言できないのはなぜClass<? extends B>
ですか?
public class Foo<B> {
public void doSomething(B argument) {
Class<? extends Object> type = argument.getClass();
}
}
この問題は、Java の構文では getClass() が定義されたクラスに一致する型を返すと言うことができないことであり、これはコンパイラに関する限り特別なケースではありません。したがって、結果をキャストする必要があります。
連鎖などで型を指定できるようにしたい場合が多いthis
ので、いつかはこの機能を搭載してほしいです。
あなたは書くことができます
Class<? extends this> getClass();
また
public this clone(); // must return a type of this class.
また
class ByteBuffer {
this order(ByteOrder order);
}
class MappedByteBuffer extends ByteBuffer {
}
// currently this won't work as ByteBuffer defines order()
MappedByteBuffer mbb = fc.map(MapMode.READ_WRITE, 0, fc.size())
.order(ByteOrder.nativeOrder());
Object.getClass()
is defined to return a Class, where T is the statically known type of the receiver (the object getClass() is called on). Take special note of the vertical bars, the erasure operator. The erasure of a type variable is the erasure of its leftmost bound. In your case that's the implicit bound Object. So you get back a Class, not a Class<? extends T>
.
The right way to do it is,
abstract class AbstractExecutor<E> {
public void execute() throws Exception {
List<E> list = new ArrayList<E>();
Class<E> cls = (Class<E>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
E e = cls.getConstructor(String.class).newInstance("Gate");
list.add(e);
System.out.println(format(list));
}
// ...
}
特定のオブジェクトのクラスが、格納されている型と同じであるとは限らないためです。
例えば。
Object o = "some string";
Class<Object> clazz = o.getClass(); // actually Class<String>
タイプを見ると、 のクラスを期待する必要がありObject
ますが、実際には のクラスを取得しますString
。これはどのような問題ですか?Object
は のスーパークラスでString
あるため、String
によって実装されるすべてのメソッドを実装しObject
ます。
問題は、クラスを取得するField
と、ジェネリック型ではなく実際のクラスのフィールドが返されることです。さらにMethod
、指定されたオブジェクトにオーバーライド メソッドがある場合、正しいメソッドを呼び出すことはできますが、その逆を行って、指定されたオブジェクトで機能するメソッドの実装を見つけることはできません。
たとえば、Object は を宣言しhashCode
ているため、すべてのオブジェクトにハッシュ コード メソッドがあります。ただし、次の場合は実行時例外が発生します。
Object.class.getMethod("hashCode").invoke("some string"); // works
String.class.getMethod("hashCode").invoke(new Object()); // fails
これは、 のMethod
オブジェクトhashCode
がString
. 文字のシーケンスからハッシュ コードを生成することを期待していますが、提供されたオブジェクトにはメソッドが動作するための char 配列がないため、失敗します。
getMethod
つまり、次のように動作するように見えますが、 によって返される実際のメソッドが のハッシュ コード メソッドであるため、動作しませんString
。
Object obj = "string";
Class<Object> clazz = obj.getClass();
clazz.getMethod("hashCode").invoke("another string");
これがすべてですgeneric type erasure
。ここから:
ジェネリック型のすべての型パラメーターをそれらの境界またはオブジェクト (型パラメーターが無制限の場合) に置き換えます。したがって、生成されたバイトコードには、通常のクラス、インターフェース、およびメソッドのみが含まれます。【コンパイル時】
Class
したがって、実際の型を取得することはできませんが、 orB
のみです。?
? extends Object
<B extends SomeClass>
境界が onlyではなくに変わる場合は、 type のオブジェクトを<B>
フェッチできます。Class
<? extends SomeClass>