简体   繁体   中英

How does the Java cast operator work?

I am trying to debug an issue involving a ClassCastException in Java. In the interest of solving the issue I need to know what is going on when I cast from Object to a specific type. Can anyone explain to me how the Java cast operator works at the Java level and the JVM level?

Is the JLS good enough?

Casting conversion is applied to the operand of a cast operator (§15.16): the type of the operand expression must be converted to the type explicitly named by the cast operator. Casting contexts allow the use of:

  • an identity conversion (§5.1.1)
  • a widening primitive conversion (§5.1.2)
  • a narrowing primitive conversion (§5.1.3)
  • a widening reference conversion (§5.1.5) optionally followed by an unchecked conversion (§5.1.9)
  • a narrowing reference conversion (§5.1.6) optionally followed by an unchecked conversion
  • a boxing conversion (§5.1.7)
  • an unboxing conversion (§5.1.8).

Actually, maybe this part is more relevant:

The detailed rules for compile-time legality of a casting conversion of a value of compile-time reference type S to a compile-time reference type T are as follows:

  • If S is a class type:
    • If T is a class type, then either | S | <: | T |, or | T | <: | S |; otherwise a compile-time error occurs. Furthermore, if there exists a supertype X of T , and a supertype Y of S , such that both X and Y are provably distinct parameterized types (§4.5), and that the erasures of X and Y are the same, a compile-time error occurs.
    • If T is an interface type:

      • If S is not a final class (§8.1.1), then, if there exists a supertype X of T , and a supertype Y of S , such that both X and Y are provably distinct parameterized types, and that the erasures of X and Y are the same, a compile-time error occurs. Otherwise, the cast is always legal at compile time (because even if S does not implement T , a subclass of S might).
      • If S is a final class (§8.1.1), then S must implement T , or a compile-time error occurs.

    • If T is a type variable, then this algorithm is applied recursively, using the upper bound of T in place of T .
    • If T is an array type, then S must be the class Object , or a compile-time error occurs.
  • If S is an interface type:
    • If T is an array type, then T must implement S , or a compile-time error occurs.
    • If T is a type that is not final (§8.1.1), then if there exists a supertype X of T , and a supertype Y of S , such that both X and Y are provably distinct parameterized types, and that the erasures of X and Y are the same, a compile-time error occurs. Otherwise, the cast is always legal at compile time (because even if T does not implement S , a subclass of T might).
    • If T is a type that is final , then:
      • If S is not a parameterized type or a raw type, then T must implement S , and the cast is statically known to be correct, or a compile-time error occurs.
      • Otherwise, S is either a parameterized type that is an invocation of some generic type declaration G , or a raw type corresponding to a generic type declaration G . Then there must exist a supertype X of T , such that X is an invocation of G , or a compile-time error occurs. Furthermore, if S and X are provably distinct parameterized types then a compile-time error occurs.
  • If S is a type variable, then this algorithm is applied recursively, using the upper bound of S in place of S .
  • If S is an array type SC [], that is, an array of components of type SC :
    • If T is a class type, then if T is not Object , then a compile-time error occurs (because Object is the only class type to which arrays can be assigned).
    • If T is an interface type, then a compile-time error occurs unless T is the type java.io.Serializable or the type Cloneable , the only interfaces implemented by arrays.
    • If T is a type variable, then:
      • If the upper bound of T is Object or the type java.io.Serializable or the type Cloneable , or a type variable that S could legally be cast to by recursively applying these rules, then the cast is legal (though unchecked).
      • If the upper bound of T is an array type TC[] , then a compile-time error occurs unless the type SC[] can be cast to TC[] by a recursive application of these compile-time rules for casting.
      • Otherwise, a compile-time error occurs.
    • If T is an array type TC [], that is, an array of components of type TC , then a compile-time error occurs unless one of the following is true:

    • TC and SC are the same primitive type.
    • TC and SC are reference types and type SC can be cast to TC by a recursive application of these compile-time rules for casting.

Perfectly clear now, isn't it? :D

In other words, this is the best I can do without knowing more details about your problem.

A likely cause of class cast mystifcation is that not only do the types have to match but also they must be loaded by the same classloader.

You should be able to dump not only the type hierarchy but also the identity of the classloader for each class.

These kind of problems are not uncommon in appserver-style environments where application code and infratructure code are deliberately isolated - for example if system classes are accidentally included in applciation JARs you can have two copies of the "same" class inthe JVM and life gets confusing

其他有用且权威的参考资料可在Java虚拟机规范中找到,特别是§2.6.5,“缩小参考转换”,尤其是checkcast指令的定义。

Casting asserts that the runtime type of an object is compatible with the given static type, and thus allows you to call methods of that type on the object.

Here obj is a Integer object, but only accessible though an Object reference:

Object obj = new Integer(1);

Casting lets you treat it as an Integer (or some superclass of Integer) again:

System.out.println(((Integer) obj).intValue());

ClassCastException occours when the static type given does not match the runtime type of the object:

System.out.println(((Float) obj).intValue()); // runtime error

You can find the runtime type of any object by using getClass() and the various Class methods:

System.out.println(obj.getClass()); // prints "class java.lang.Integer"

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