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
? 是不是总是从代码中清楚地知道它总是能够安全地进行演员表演?
有什么方法可以得到一个Class
从obj
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确实是使用类型擦除实现的,但这并不意味着丢失所有类型信息。 编译器会将类型擦除到它可以的最低边界。
所以
generics是复杂的,它们并不总能做你想要的,但有很多方法可以解决很多问题(通过改进边界,通过reflection访问运行时类型信息,以及传递类对象)。 类型擦除实际上是一个非常聪明的解决方案,不应该收到它的大部分坏消息。
由于类型擦除,运行时不保留通用数组的类型信息。 实际上,JVM在内部将所有通用数组视为Object []。
如果要获取运行时类型,最好的选择可能只是在数组中的第一项上调用getClass()。 您显然需要找到一种处理空案例的方法,以及包含的对象是多种类型的情况等。