为什么Class.getClass()可以与Class.cast()返回类型不同?

时间:2011-10-27 16:25:30

标签: java casting

我希望你能帮助我解决这个问题。

我一直在寻找这个问题的答案,但我能找到的只与通用类型用法或关于反射的一般说明有关。

假设我们有一个父类和一个扩展该父类的子类。所以,见下文:

Parent v = new Child();

如果我v.getClass(),则返回Child。但是,如果我生成v.getClass().cast(),则会返回Parent类型的对象。

任何人都知道它为什么会发生?我还看了一下Java API文档,找不到原因...

感谢您的任何想法。

3 个答案:

答案 0 :(得分:19)

对象的运行时类型与变量或表达式的编译时类型之间存在重要区别。表达式的编译时类型只能 从其组件的编译时类型确定。作为这些表达式的值的对象的运行时类型可以从表达式的参数的运行时类型中确定,只要它们与编译时类型兼容即可。

为了说明这一点,请在您的特定代码示例中填写:

  • 变量v具有编译时类型Parent,但分配给它的值的运行时类型将为{{ 1}}。
  • 表达式Child将具有编译时类型v.getClass()(表示Class<? extends Parent>类型或其子类之一的类对象。)。它在运行时的值为Parent,其类型为Child.class
  • 表达式Class<Child>将具有编译时类型v.getClass().cast(obj)。它的运行时类型将是 Parent 的运行时类型,因为它的运行时值实际上将是obj本身。 (也就是说,如果obj属于可分配给obj类型变量的类型,否则Child将抛出cast()

答案 1 :(得分:1)

  

我一直在寻找这个问题的答案,但我能找到的只与通用类型用法或关于反射的一般说明有关。

您收到Class<Parent>,因为这是编译时类型。

//compiletime v is of type Parent
Parent v = new Child(); 
//The class of a Parent object is either the Parent class or a child Class
Class<? extends Parent> cls = v.getClass();
//The return type of cast is the at compile time known upper bound, here it is 
//Parent, which is true since every Child object is also a Parent object.  
cls.cast(...);
//Note that this will throw a runtime exception, since it will perform a 
//cast to child at runtime. The cast uses the Child class at runtime and
//fails for other instances of Parent.
cls.cast(new Parent());

这里有一个简单的例子,说明你可以使用它。

class Test<T>{
  public Test(Class<T> cls){clazz = cls;}
  ArrayList<T> list = ...;
  Class<T> clazz;
  void add(Object o){
     list.add((T)o);//Cast does nothing at runtime
     list.add(clazz.cast(o)); //casts o to T
  }
}

表单(T)中的正常强制转换o在java中不起作用,因为泛型类型T在运行时是未知的。 jvm只能看到永不失败的上界(Object)强制转换。使用cast方法来引用实际的类是一种解决方法。

答案 2 :(得分:0)

这是因为getClass()方法和泛型的设计。

出于兼容性原因,getClass()方法尚未生成泛型,因此它返回类型为

的实例
Class<?> 

不是

Class<Child> 
正如你所料,

Class<?> 

表示类型参数为Object的泛型类型。

所以,返回类型

Class<?>.cast() 

方法是Object。即这种方法的通用性质不起作用。

你可以写

v3 = ( (Class<Child>) v.getClass() ).cast(v2);

但这是没有意义的,因为你可以写

v3 = ( Child ) v.getClass().cast(v2);

另外,您应该记住,泛型只能在编译时工作。即genercis仅用于IDE的类型检查。在运行时,所有泛型都是

<?>

因此,实际上,cast()方法在运行时不执行任何操作。当您拥有类型

的实例时,这只是一个存根
Class<something>