【发布时间】:2011-04-29 23:38:09
【问题描述】:
在这样的函数中:
<T> void foo(T obj)
obj.getClass() 的类型是 Class<?> 而不是 Class<? extends T>。为什么?
以下代码可以正常工作:
String foo = "";
Class<? extends String> fooClass = foo.getClass();
所以T#getClass() 的签名似乎返回了Class<? extends T>,对吧?
如果T 确实是泛型,为什么签名会有所不同?
为了克服这个问题(并让我更清楚我在游荡什么),我实现了这个功能:
@SuppressWarnings("unchecked") static <T> Class<? extends T> classOf(T obj) {
return (Class<? extends T>) obj.getClass();
}
又是一个问题:为什么这里需要演员阵容而不是String 案例?为什么是
SuppressWarnings 需要吗?从代码中是否总是清楚地表明它总是能够安全地执行此转换?
有什么方法可以从obj 获得Class<? extends T>?如果是,如何?如果没有,为什么不呢?
一种方法是使用classOf。那会很安全,对吧?如果这总是安全的并且提供了一种真正获得Class<? extends T>(而不是Class<?>)的安全方法,那么为什么Java 中没有这样的功能?或者有吗?
那个案子怎么样:
<T> void bar(T[] array)
array.getClass().getComponentType() 再次返回 Class<?> 而不是 Class<? extends T>。为什么?
我已经实现了这个功能:
@SuppressWarnings("unchecked") static <T> Class<? extends T> classOf(T[] array) {
return (Class<? extends T>) array.getClass().getComponentType();
}
这还能安全使用吗?
澄清更多我想知道的。考虑这个演示代码:
static interface I<T> {
Class<? extends T> myClass();
}
static class A implements I<A> {
public Class<? extends A> myClass() {
return this.getClass();
}
}
static <T> void foo(I<T> obj) {
Class<? extends T> clazz = obj.myClass(); // this works
}
这很好用。但Object#getClass() 则不然。
为什么不可能有一个像ClassInstance<T> 这样的通用接口和函数getClass() 并且每个Java 对象都自动实现它?这将具有我所说的对解决方案的改进,使其从非泛型基类 Object 扩展。
或者将Object 作为一个泛型类:
static abstract class Object<T> {
abstract Class<? extends T> myClass();
}
static class B extends Object<B> {
public Class<? extends B> myClass() {
return this.getClass();
}
}
static <T> void bar(Object<T> obj) {
Class<? extends T> clazz = obj.myClass(); // this works
}
现在将myClass() 视为getClass() 并考虑编译器会自动将其添加到每个类中。它会解决很多这样的选角问题。
我要说的主要问题是:为什么不是这样制作的?
或者换个说法:Here, I describe in more detail the solution of such classOf function which overcomes the problem.为什么不是这样,即为什么原来的功能不是这样?
(我真的不想得到这样的答案:Java 现在的工作方式,即从定义此函数的非泛型 Object 扩展,这使得这不可能。我在问为什么它不是' t 以某种不同的方式解决,所以它本来是可能的。)
【问题讨论】:
-
回答您的编辑...这不会编译,因为即使 A 是 B 的子级,Class 也不是 Class 的子级。您将有不兼容的返回类型。 - 你让它工作的唯一方法是如果一切都返回 Class extends Object> 基本上就是现在的样子。
-
@CurtainDog:两个示例都可以编译(嗯,将第二个示例中的名称
Object更改为 sth.else)。但无论如何,我的问题并不是关于我怎么能做到这一点,而是更多关于为什么会这样。已经有可能(例如我展示的方式)使getClass()返回正确的类型。那为什么不这样呢? -
我认为当他们修补编译器以返回 Class。