Java:getClass()是有界类型

Java:getClass()是有界类型,java,type-erasure,type-parameter,Java,Type Erasure,Type Parameter,我在使用泛型时注意到了一些东西。在下面的示例中,doStuff1编译,但doStuff2不编译: public <T extends Foo> void doStuff1(T value) { Class<? extends Foo> theClass = value.getClass(); } public <T extends Foo> void doStuff2(T value) { Class<? extends T> t

我在使用泛型时注意到了一些东西。在下面的示例中,
doStuff1
编译,但
doStuff2
不编译:

public <T extends Foo> void doStuff1(T value) {
    Class<? extends Foo> theClass = value.getClass();
}

public <T extends Foo> void doStuff2(T value) {
    Class<? extends T> theClass = value.getClass();
}
public void doStuff1(T值){

类您不能确定
value
实际上是一个T,它也可以是T的子类。
getClass()
确实返回
value
的“真实”类,但您不能确定它不是,因此它必须阅读
Class非常好的问题

java泛型的全部问题是它们在旧的虚拟机中不存在。 Sun决定添加通用支持,而现有虚拟机不支持它们

这可能是一个大问题,因为当它们发布新的Java时,旧的虚拟机将无法运行为最新版本的Java编写的任何代码,并且它们将无法支持旧的虚拟机

因此,他们决定以一种也可以在旧虚拟机中运行的方式实现泛型。 他们决定从字节码中删除它们

所以整个故事都是关于JVM的后台支持

编辑:但这可能与问题无关。请看库奇肯的答案

另外,我的猜测是,在第二种情况下,cast是
Class工具提供了一些工具来解决这个限制,并帮助您获得有界类型的类型(so类)

如本说明页第一行所述:

由于类型擦除,您不能同时传递泛型类对象 运行时--您可以强制转换它们并假装它们是泛型的, 但事实并非如此

Guava提供了TypeToken,它使用基于反射的技巧来允许 您需要操作和查询泛型类型,即使在运行时也是如此

其思想是获取(或创建)一个有界类型的,然后您可以请求它的类型


我认为这个答案有点离题,因为它不能直接回答问题(“为什么”部分),但它可以修复不可编译的方法,它可以生成代码来解决问题并给出为什么部分的答案,并且肯定会帮助其他人寻找“Java:-how-getClass()”的有界类型“

如果
getClass()
返回
Class请考虑以下程序:

var a = new ArrayList<String>();
var b = new ArrayList<Integer>();
var aType = a.getClass();        
var bType = b.getClass();        

if (aType == bType) {
  ...
}

当然,这意味着您可能需要求助于未经检查的强制转换,以使编译器理解不可转换类型的类对象可能毕竟是相同的…

有一种情况需要说明,这种向后兼容性所造成的麻烦比破坏它所带来的麻烦要多,但这是Sun决定的。-)100%同意。这一点可能是我唯一讨厌Java的地方^^^这个问题不是关于类型擦除,而是关于类层次结构。请看我的答案。即使T不是类型参数,而是任何非最终类,那么getClass()还回个Class@kutschkem你说得对。我应该在开始写答案之前考虑一下这些问题,假设我理解了这个问题。^^;@Lake你可能有一部分是对的。毕竟,我没有意识到method2没有编译:-/我认为它可能与擦除和边界相结合有关?弄清楚这一点会让我的头部受伤;我讨厌计算泛型类型边界,即使它还不算太晚。我建议开始并查看搜索规则;这可能是JVM如何在对象的运行时类上发挥其静态魔法的产物。嗯,你的观点呢?
class嗯,我的错,我没有仔细阅读,没有看到你的第二种方法od没有编译。我不知何故认为问题在于为什么返回值是Class。你会用什么来代替“
”?未经检查的强制转换?@5gon12eder——是的。该方法从根本上是不安全的;调用者必须确保它在特定用例中有意义。这是否意味着
静态类
String s = "s";
Object o = s;
public <T extends List> void doStuff2(T value) {
   Class<? extends T> theClass = (Class<? extends T>) value.getClass();
}
static <X> Class<? extends X> myGetClass(X x){ ... }
var a = new ArrayList<String>();
var b = new ArrayList<Integer>();
var aType = a.getClass();        
var bType = b.getClass();        

if (aType == bType) {
  ...
}
@SuppressWarnings("unchecked")
<T> Class<? extends T> getTypedClassOf(T t) {
   return (Class) t.getClass();
}