在这段代码中,为什么不能将 type 声明为Class<? extends B>
?
public class Foo<B> {
public void doSomething(B argument) {
Class<? extends Object> type = argument.getClass();
}
}
在这段代码中,为什么不能将 type 声明为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());
这就是全部generic type erasure
。从这里:
如果类型参数是无界的,则将泛型类型中的所有类型参数替换为其边界或 Object。因此,生成的字节码只包含普通的类、接口和方法。[在编译时]
所以你不能得到Class
实际类型,B
但只有?
or ? extends Object
。
如果您的界限将变成<B extends SomeClass>
而不是<B>
仅,那么您可以获取Class
类型的对象<? extends SomeClass>
。
Object.getClass()
被定义为返回一个类,其中 T 是接收者的静态已知类型(对象 getClass() 被调用)。请特别注意竖线,即擦除运算符。类型变量的擦除是其最左边界的擦除。在您的情况下,这是隐式绑定对象。所以你得到一个 Class,而不是一个Class<? extends T>
.
正确的做法是,
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>
通过查看类型,您应该期望 Class for Object
,但实际上您会得到类 for 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
对象 forhashCode
期待一个String
. 它期望从字符序列生成哈希码,但提供的对象没有用于该方法工作的 char 数组,因此它失败了。
这意味着以下看起来应该可以工作,但不会因为返回的实际方法getMethod
是String
.
Object obj = "string";
Class<Object> clazz = obj.getClass();
clazz.getMethod("hashCode").invoke("another string");