Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

java

casting

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.

like image 716
Sidney de Moraes Avatar asked Oct 27 '11 16:10

Sidney de Moraes


2 Answers

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> (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)
like image 147
millimoose Avatar answered Oct 20 '22 19:10

millimoose


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.

like image 1
josefx Avatar answered Oct 20 '22 19:10

josefx