How does the Java cast operator work?

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? 😀

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

Leave a Comment