Java:T obj; obj.getClass()的类型是Class 而不是Class 。 为什么?

在这样的function:

 void foo(T obj) 

obj.getClass()的类型是Class而不是Class Class 。 为什么?

以下代码工作正常:

 String foo = ""; Class fooClass = foo.getClass(); 

所以T#getClass()的签名似乎返回一个Class Class ,对吗?

如果T真的是通用的,为什么签名会有所不同?

为了克服这个问题(并使我更清楚地了解我的内容),我实现了这个function:

 @SuppressWarnings("unchecked") static  Class classOf(T obj) { return (Class) obj.getClass(); } 

问题是:为什么需要演员而不是String案例? 为什么需要SuppressWarnings ? 是不是总是从代码中清楚地知道它总是能够安全地进行演员表演?

有什么方法可以得到一个Classobj Class ? 如果有,怎么样? 如果没有,为什么不呢?

一种方法是使用classOf 。 那会安全的,对吧? 如果这总是安全的,并提供一个真正的方法来真正获得一个Class Class (而不是Class ),为什么Java中没有这样的函数? 或者有吗?


那个案子怎么样:

  void bar(T[] array) 

array.getClass().getComponentType()再次返回一个Class而不是一个Class Class 。 为什么?

我已经实现了这个function:

 @SuppressWarnings("unchecked") static  Class classOf(T[] array) { return (Class) array.getClass().getComponentType(); } 

这又安全吗?


澄清我想知道的更多内容。 考虑这个演示代码:

 static interface I { Class myClass(); } static class A implements I { public Class myClass() { return this.getClass(); } } static  void foo(I obj) { Class clazz = obj.myClass(); // this works } 

这很好用。 但是对于Object#getClass()

例如,为什么不能使用函数getClass()和每个Java对象自动实现此类通用接口(如ClassInstance getClass() ? 这将完全是我正在谈论的解决方案,以使其从非generics基类Object扩展。

或者将Object作为generics类:

 static abstract class Object { abstract Class myClass(); } static class B extends Object { public Class myClass() { return this.getClass(); } } static  void bar(Object obj) { Class clazz = obj.myClass(); // this works } 

现在将myClass()视为getClass()并考虑编译器会自动将其添加到每个类。 它会解决很多这些铸造问题。

我说的主要问题是:为什么不是这样做的?


或者用不同的词再说一遍: 在这里,我更详细地描述了克服这个问题的classOf函数的解决方案。 为什么它不是这样的,即为什么原始function不是这样的?

(我真的不想得到这样的答案:Java现在的工作方式,即从定义此函数的非genericsObject扩展,使得这不可能。我在问为什么它不能以某种方式解决,所以这本来是可能的。)

基本问题是getClass()不返回类,因为它在Object级别定义。 即它被公认为一个扩展对象的类。 他们可以定义getClass()之类的。

 Class getClass() { /**/ } 

而是它的

 Class getClass() 

这意味着generics不了解getClass返回的内容。

在Java中,generics只是更安全开发的源级工具。

JVM对generics一无所知。 Java编译器抛弃了这些信息,所有generics类型实际上只是运行时的Object引用。 为了弥补编译器插入必要的强制转换。 此过程称为Type Erasure (Google!)。

 List x = new ArrayList(); x.add("hello"); String hello = x.get(0); 

在运行时变为以下

 List x = new ArrayList(); x.add("hello"); String hello = (String) x.get(0); 

要解决您的问题,您可以尝试调查数组中的各个元素( arr[0].getClass() )。

这里有几个不完全准确的答案。 generics确实是使用类型擦除实现的,但这并不意味着丢失所有类型信息。 编译器会将类型擦除到它可以的最低边界。

所以被删除为String; 这就是为什么String上的getClass返回Class <? extends String>。 你的无界会被删除为对象; 所以getClass返回Class <? extends Object>,即Class <?>

generics是复杂的,它们并不总能做你想要的,但有很多方法可以解决很多问题(通过改进边界,通过reflection访问运行时类型信息,以及传递类对象)。 类型擦除实际上是一个非常聪明的解决方案,不应该收到它的大部分坏消息。

由于类型擦除,运行时不保留通用数组的类型信息。 实际上,JVM在内部将所有通用数组视为Object []。

如果要获取运行时类型,最好的选择可能只是在数组中的第一项上调用getClass()。 您显然需要找到一种处理空案例的方法,以及包含的对象是多种类型的情况等。