简体   繁体   中英

Why Class.getClass() can be different from Class.cast() return type?

I hope you can assist me on this matter.

I've been looking for answers to this question but all I could find was related to generic type usage or general instructions about reflection.

Say we have a parent class and a child class which extends that parent. So, see below:

Parent v = new Child();

If I make v.getClass() it returns Child . However, if I make v.getClass().cast() it returns an object from type Parent .

Anyone knows why it happens? I also took a look at the Java API documentation and couldn't find a reason...

Thanks for any thoughts.

There's an important distinction between what the runtime type of an object and the compile-time type of a variable or expression is. The compile-time type of an expression can only be determined from the compile-time types of its components. The runtime types of objects that are the values of these expressions may be determined from the runtime types of the parameters of the expression, as long as they are compatible with the compile-time types.

To illustrate this, in your specific code sample:

  • The variable v has the compile-time type Parent , but the runtime type of the value assigned to it will be Child .
  • The expression v.getClass() will have the compile-time type Class<? extends Parent> Class<? extends Parent> (a class object representing either the Parent type or one of its subclasses.). Its value at runtime will be Child.class which is of type Class<Child> .
  • The expression v.getClass().cast(obj) will have the compile-time type Parent . It's runtime type will be the runtime type of obj , because its runtime value will, in fact, be obj itself. (That is, if obj is of a type that's assignable to a variable of type Child , otherwise cast() will throw a ClassCastException )

I've been looking for answers to this question but all I could find was related to generic type usage or general instructions about reflection.

You receive a Class<Parent> as that is the compile time type.

//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());

Here a simplified example for what you can use it.

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
  }
}

A normal cast in the form (T)o does not work in java as the generic type T is not known at runtime. The jvm only sees the upper bound (Object) cast which never fails. Using the cast method with a reference to the actual class instead is a workaround for this.

This is because of design of getClass() method and generics.

For compatibility reasons, getClass() method have not made generic, so it returns instance of type

Class<?> 

not

Class<Child> 

as you could expect.

Class<?> 

means generic type with type parameter of Object.

So, the return type of

Class<?>.cast() 

method is Object. Ie generic nature of this method does not work.

You can write

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

but this is senseless since you can just write

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

Also, you should remember, that generics work only at compile time. Ie genercis are only for type checking at your IDE. At runtime all generics are

<?>

So, actually, cast() method does nothing at runtime. This is only a stub to use when you have instances of type

Class<something>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM