5.5 Casting Conversion

Sing away sorrow, cast away care.

-Miguel de Cervantes (1547-1616),
Don Quixote (Lockhart's translation), Chapter viii

Casting conversion is applied to the operand of a cast operator (§15.15): 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.4), or a narrowing reference conversion (§5.1.5). Thus casting conversions are more inclusive than assignment or method invocation conversions: a cast can do any permitted conversion other than a string conversion.

Some casts can be proven incorrect at compile time; such casts result in a compile-time error.

A value of a primitive type can be cast to another primitive type by identity conversion, if the types are the same, or by a widening primitive conversion or a narrowing primitive conversion.

A value of a primitive type cannot be cast to a reference type by casting conversion, nor can a value of a reference type be cast to a primitive type.

The remaining cases involve conversion between reference types. The detailed rules for compile-time correctness checking of a casting conversion of a value of compile-time reference type S (source) to a compile-time reference type T (target) are as follows:

See §8 for the detailed specifications of classes, §9 for interfaces, and §10 for arrays.

If a cast to a reference type is not a compile-time error, there are two cases:

If a run-time exception is thrown, it is a ClassCastException (§11.5.1.1, §20.22).

Here are some examples of casting conversions of reference types, similar to the example in §5.2:


public class Point { int x, y; }

public interface Colorable { void setColor(int color); }
public class ColoredPoint extends Point implements Colorable { int color; public void setColor(int color) { this.color = color; } }

final class EndPoint extends Point { }
class Test { public static void main(String[] args) { Point p = new Point(); ColoredPoint cp = new ColoredPoint(); Colorable c;
// The following may cause errors at run time because // we cannot be sure they will succeed; this possibility // is suggested by the casts: cp = (ColoredPoint)p; // p might not reference an // object which is a ColoredPoint // or a subclass of ColoredPoint c = (Colorable)p; // p might not be Colorable
// The following are incorrect at compile time because // they can never succeed as explained in the text: Long l = (Long)p; // compile-time error #1 EndPoint e = new EndPoint(); c = (Colorable)e; // compile-time error #2
}
}

Here the first compile-time error occurs because the class types Long and Point are unrelated (that is, they are not the same, and neither is a subclass of the other), so a cast between them will always fail.

The second compile-time error occurs because a variable of type EndPoint can never reference a value that implements the interface Colorable. This is because EndPoint is a final type, and a variable of a final type always holds a value of the same run-time type as its compile-time type. Therefore, the run-time type of variable e must be exactly the type EndPoint, and type EndPoint does not implement Colorable.

Here is an example involving arrays (§10):


class Point {

	int x, y;

Point(int x, int y) { this.x = x; this.y = y; }
public String toString() { return "("+x+","+y+")"; }
}
public interface Colorable { void setColor(int color); }
public class ColoredPoint extends Point implements Colorable { int color; ColoredPoint(int x, int y, int color) { super(x, y); setColor(color); }

public void setColor(int color) { this.color = color; }
public String toString() { return super.toString() + "@" + color; }
}
class Test { public static void main(String[] args) { Point[] pa = new ColoredPoint[4]; pa[0] = new ColoredPoint(2, 2, 12); pa[1] = new ColoredPoint(4, 5, 24); ColoredPoint[] cpa = (ColoredPoint[])pa; System.out.print("cpa: {"); for (int i = 0; i < cpa.length; i++) System.out.print((i == 0 ? " " : ", ") + cpa[i]); System.out.println(" }"); }
}

This example compiles without errors and produces the output:

cpa: { (2,2)@12, (4,5)@24, null, null }

The following example uses casts to compile, but it throws exceptions at run time, because the types are incompatible:


public class Point { int x, y; }

public interface Colorable { void setColor(int color); }
public class ColoredPoint extends Point implements Colorable {
int color;

public void setColor(int color) { this.color = color; }
}
class Test { public static void main(String[] args) {
Point[] pa = new Point[100];
// The following line will throw a ClassCastException: ColoredPoint[] cpa = (ColoredPoint[])pa;

System.out.println(cpa[0]);

int[] shortvec = new int[2];

Object o = shortvec;
// The following line will throw a ClassCastException: Colorable c = (Colorable)o;

c.setColor(0);
}
}