Cast Operator

Changes the type of an expression.

The cast operator (often simply called cast) changes or specifies the type of an expression, throwing a ClassCastException if its argument cannot be coerced to the specified type.

Casts can be used to perform certain automatic conversions, broaden or shrink the type of an expression, change the type being instantiated by a lambda or method reference, clarify ambiguous method invocations, and more.

Syntax

Cast Operators are used in cast expressions. Cast expressions can be written in the following forms:

1 ( primitive-type ) primitive-castable-expression
2 ( reference-type ) reference-castable-expression
2 ( reference-type interface-type-list ) reference-castable-expression

where...

primitive-type is any one of the types: boolean, byte, short, char, int, long, float, or double.
primitive-castable-expression is an expression of one of the following types:
  • the application of any unary operator (including another cast),
  • a literal,
  • a parenthesized expression,
  • a reference to a field or variable,
  • an array component,
  • a method invocation,
  • a class instance creation expression that instantiates one of the wrapper types (e.g., new Integer(10)),
  • the keyword this (possibly qualified by a type), specifically when referring to one of the wrapper types,

Other types are syntactically, but not semantically permitted.

Syntactically, a primitive-castable-expression can also be any one of the following expressions, but a primitive-type–cast may only be applied to a type convertible to a primitive type, and none of the following types can be converted to a primitive type through a single cast.
  • any type of array creation expression,
  • a method reference,
  • a class literal.
reference-type is any non-primitive type. This can be either a user-defined type (class, interface including @interface, or enum), a type parameter variable, or any array type (including one with a primitive component type).
reference-castable-expression is an expression of one of the following types:
  • lambda expressions
  • the application of any one of the following operators:
    • the cast operator,
    • the logical negation operator,
    • the bitwise negation operator,
    • the post-increment operator,
    • the post-decrement operator,
  • any type of array creation expression,
  • a method reference,
  • the keyword this (possibly qualified by a type),
  • a class literal,
  • a literal,
  • a parenthesized expression,
  • a class instance creation expression,
  • a reference to a field,
  • an array component,
  • a method invocation,
  • an expression name,
  • a lambda expression.
interface-type-list is a sequence that specifies additional types, each of which must be an interface type. Each element of the sequence is comprised of the & token (used as a separator between the types specified) followed by the type itself. Each type in the sequence must be an interface.

Syntax Elements

1 A normal cast to a primitive type.

2 A normal cast to a reference type.

3 An intersection cast. Intersection casts always use reference types.

Behavior

Every expression has a type which is known at compile time.Every expression is classified as either a standalone or a poly expression. A standalone expression's type can be determined from its contents whereas a poly expression's type can be determined from its context. Casting can have runtime effects, but is usually used to change the type of an expression without changing the value, which is a compile-time operation; using the cast operator on some expression forms a new expression whose type is that specified in the cast.

A cast expression can affect the runtime value of its operand. Notable cases include the case that the operand is a lambda expression or method reference expression and the case that either the operand or the type being casted to is primitive.

Conversions

Casting operates on its argument by performing a casting conversion. A casting conversion is the attempted change of a value's type to the type specified by the cast.

  1. Primitive-Type --> Primitive-Type Conversion
    1. Widening Primitive Conversion
      1. Integral --> Integral
        1. byte --> short, int, long
          short --> int, long
          int --> long
        2. char --> int, long
      2. float --> double
      3. Integral --> Floating
        1. byte, short, char --> float
          byte, short, char, int --> double
        2. int, long --> float
          long --> double
    2. Narrowing Primitive Conversion
      1. double --> float
      2. short, char, int, long --> byte
        short, int, long --> char
        char, int, long --> short
        long --> int
      3. float, double --> byte, short, char, int, long
    3. byte --> char
  2. Primitive Type --> Reference Type Conversion (Boxing)
    1. Boxing of boolean, byte, short, char, int, long
    2. Boxing of float, double
    3. Mandated caching of integers, characters, and booleans
  3. Reference Type --> Primitive Type Conversion (Unboxing)
  4. Reference Type --> Reference Type Conversion
    1. Widening (Subtype --> Supertype)
    2. Narrowing (Supertype --> Subtype)

Primitive --> Primitive Conversions

All primitive types can be cast between each other except for the type boolean, which cannot be cast to or from any other primitive type (since it is not numeric).

Widening Primitive Conversion

Widening primitive conversion is performed when an expression of a smaller numeric primitive type is cast to a larger numeric primitive type, such as in casting an int expression to type long, or a short to type double.

For integral types

For integral (non-decimal) types, the value resulting from a widening cast conversion always exactly represents the original value, except when casting a negative byte to type char (see byte --> char). Integral numeric types are ordered by size as follows:

byte < short < int < long
char is equal in byte-size to short, but is unsigned.

If any such smaller type is cast to a larger type, the conversion will occur without loss of information and the larger-type value will exactly represent the same as the smaller-type value. This is because a larger such type can represent all of the values that the smaller such type can (e.g. any byte value is also a valid int value).

A cast of a value from a smaller such type to a larger such type performs a two's-complement sign-extension on the binary data of the value (extending the sign bit) to fill the bits of the larger type.

Converting a char to a wider integral type (i.e., to int or long) involves a zero-extension of the value (i.e., bits introduced by the larger type are set to 0). Therefore, casting from char to int or long never changes the value being cast.

float --> double

Conversion of a float to type double results in a double value that represents the exact same number as the original float value.

Integral to Floating Point Conversions

Converting an integral-type value to a floating point type performs IEEE 754 rounding with round-to-nearest mode. The resulting floating point number is the representable value that is nearest to the source value, with ties between two potential floating point numbers being broken by picking the one whose least significant bit is zero (i.e., the one that is farthest from 0).

Conversion from byte, short, or char to float will always result in a float that exactly represents the same number as the original value. Conversion from byte, short, char, or int to double will result in a double that exactly represents the same number as the source value.

Conversion of large integral types to floating point types, i.e.

undergoes IEEE 754 rounding with round-to-nearest mode to arrive at a floating point value.

Narrowing Primitive Conversion

double to float conversion performs IEEE 754 rounding. Infinity values and NaN are preserved. That is, casting NaN or positive or negative Infinity from double to float results in the exact same value, but of type float.

Integral-type values, when cast to a smaller integral type, lose their most significant bits so as to fit into the smaller integral type. All signed integral types (byte, short, int, and long) use the most-significant bit (leftmost bit) to negativity, and the remaining bits to represent value. The unsigned char type uses all its bits to represent value. This can cause the sign to change when casting a larger integral type to a smaller integral type, including in the case of casting from char to byte, where the result may be negative despite no possible char value being negative.

Floating point to integral conversions

Conversion of a floating point to an integral value rounds the floating point number to the nearest integer value, picking the integer closest to zero if two integers are equidistant to the original floating point value, unless the floating point value is NaN in which case the result of the cast conversion is 0, of type specified by the cast.

A check is then made to determine if the integer value obtained is a valid:

In either case, if the rounded integer value is a valid element, it is the result of the cast expression (if casting to long or int), or the value is converted from int to the smaller, integral, primitive type via primitive integral narrowing conversion.

If the rounded integer value is not a valid element, then the closest valid long (if casting to long) or int (otherwise) is used. This is maintained in the case that the floating point value is positive or negative Infinity, in which case the integer value is either the maximum or minimum value for the long (if casting to long) or int (otherwise) type. If the cast is to a type other than long or int then the int min- or max-value is converted to the target type of the cast via primitive integral narrowing conversion.

In this way, floating point values are only directly converted to either long or int, even when cast to short, char, or byte, but for these cases, an additional conversion is made from int to the target type being cast to.

byte --> char

Conversion of a byte into a char will operate in two steps:

  1. The value is converted from byte to int,
  2. then the value is converted from int to char.

Boxing (Primitive-to-Reference Cast)

Casting can induce boxing, which is a conversion that results in an object (whose type is one of the wrapper types Byte, Short, Character, Integer, Long, Float, Double, or Boolean, each a member of the java.lang package) that represents the primitive value being cast. Wrapper types and boxing are useful for generics, as generic program elements cannot be parameterized with a primitive type (e.g. List<int> is not allowed, whereas List<Integer> is).

An expression of any primitive type, can be cast to that primitive type's wrapper type. That is, an expression can cast be from type:

In addition to these casts, a primitive type expression can be cast to any supertype of the primitive type's wrapper type, including generic types or intersection types. For example, Integer implements Comparable<Integer> and so a primitive type int expression can be cast to Comparable<Integer> or even to intersection type Number & Comparable<Integer>.

The result of casting a primitive-type value to a reference type so that it is boxed is an instance of the primitive type's corresponding wrapper type that represents the primitive value that was boxed. When invoked on the result of a boxing conversion, the following methods,

will return the primitive value that was boxed, unless the value was NaN, in which case the isNaN() method for Double and Float will return true.

Caching of Boxed Values

The values:

are cached so that boxing one of the values repeatedly results in the same object.

If any of these values is boxed twice, an identity comparison (with the == operator) of the results of the two boxings always returns true. For example:
Object a = 10, b = 5 + 5;
System.out.println(a == b);

will always print

true

Unboxing (Reference-to-Primitive Cast)

Unboxing occurs when an expression of reference type is cast to an expression of primitive type. The cast operates by first attempting to narrow the reference type to the appropriate wrapper type; (the wrapper type that corresponds to the primitive type being cast to), then the cast returns a primitive type with the same value as the one represented by the value being cast (or the cast throws a NullPointerException at runtime if the reference type's value is null).

If the type of the expression being cast (primitive-castable-expression), is not a supertype of the wrapper type that corresponds to primitive-type (i.e., the wrapper type that corresponds to the cast's target type), the cast expression raises a compile-time error. For example, trying to cast an expression of type List to type int raises a compile-time error because the List expression can never evaluate to an Integer object.

If the cast is valid at compile-time but, at runtime, the actual value of the primitive-castable-expression is not an instance of the wrapper type, a ClassCastException is raised. If primitive-castable-expression evaluates to null, the cast results in a NullPointerException.

If the cast succeeds, the resulting primitive value is exactly the same as the value represented by the object that was cast. In particular, the cast is the same as the result of the corresponding value method of the wrapper type.

Reference --> Reference Conversion

Widening (Subtype --> Supertype) Conversion

Casting a reference type expression to a supertype of the expression's type never results in a compile-time error and always succeeds. Casting to a supertype can be used to change which method or constructor is invoked by a method invocation expression, or can be used to change the type of value that a lambda expression evaluates to.

Narrowing (Supertype --> Subtype) Conversion

Narrowing reference conversions always perform a run-time check to verify that the actual value that reference-castable-expression evaluates to is an instance of the reference-type (or intersection type) being cast to. If the value is not an instance, the cast fails with a ClassCastException.

A cast that performs a narrowing reference conversion can convert a reference-castable-expression:

Cast Legality

It is always permissible to cast an expression to its own type.

Reference & Primitive Cast Differences

Casting to a primitive type is treated different, syntactically, from casting to a reference type. To avoid syntactical ambiguity and ease parsing, a cast to one or more reference types cannot be applied to a unary plus or minus expression, or to a pre-increment or pre-decrement expression. This restriction holds even in the case when an intersection cast is used, (despite the lack of syntactic ambiguity with an intersection cast).

Poly Expression Arguments

The operand to a cast expression can be a poly expression (although, whether the argument is a poly expression is dependent on what kind of expression the argument is specify how).

If the argument for a cast expression is a poly expression, the target type for the poly expression is exactly the type specified by the cast, unless that specified type is generic and contains any wildcard type arguments, in which case the target type is instead the original type with each wildcard replaced with a concrete type through capture-conversion

The actual type of a poly expression is based on the type of expression the poly expression is and on the target type of the context that the poly expression is used in.

In this case, the cast expression's type is still exactly the type specified in the cast operator's parentheses, but the target type for the cast expression's argument will have no wildcards. See Poly Expressions & Wildcard Casts for details. This allows otherwise impossible lambda expressions (see below).

Intersection Casts

Specify semantic constraints for intersection cast types and behavior of intersection casts with poly expressions.

Examples

Add simple examples

Poly Expressions & Wildcard Casts

Casting a poly expression to a generic type with a wildcard type parameter causes the poly expression's finalized type to be different from the type of the cast.

Consider some generic interface:

interface Example<T> {
	void doSomething(T input);
}

The type parameter declaration <T> does not declare an explicit bound, so its bound is Object (as if declared as <T extends Object>). Instances can be obtained using lambda expressions:

Object ex = (Example<?>) a -> System.out.println(a);
// ex is an instance of Example

Due to the rules of casting with poly expressions as arguments, the lambda expression is created as an instance of Example<Object>, with Object used as the type argument rather than the wildcard ? (since wildcards are not allowed to be specified as type arguments for the instantiation of a type).

Expressions of type Example<Object> can be assigned to expressions of type Example<?>, due to subtyping rules, so the thus Example<?>-type lambda expression is permitted as the argument of the cast, and the full cast expression maintains its type, Example<?>.

This allows lambda expressions and method reference expressions to be cast to a type possessing wildcard type arguments without the need to first cast the expression to a type without wildcard arguments.

Method Invocation Selection

Casting to a supertype may be used on an argument to a method invocation expression to change which method is invoked by the expression.

class Test {
	void m(String x)	{	System.out.println("String");	}
	void m(Object x)	{	System.out.println("Object");	}
	
	void example() {
		m("abc"); // Invokes m(String) which prints "String"
		m((Object) "abc"); // Invokes m(Object) which prints "Object"
	}
}

In both cases, the same value ("abc") is passed to the methods, but which method is called is determined by the type of the expression used as an argument, not the type of the value used as an argument.

Serializable, Cloneable, & Arrays

The type of every dimension of a multidimensional array, possibly except for the last dimension's type, is an instance of java.lang.Cloneable and of java.io.Serializable (and an instance of Object, which is the supertype of Cloneable and of Serializable), and so an expression of either type (or of type Object) can be cast to any array type:

Object a = null;
System.out.println((Object[]) a); // An array of objects is also an object.
System.out.println((int[]) a); // An array of primitive-type values is also an object.
System.out.println((String[][][][][][]) a); // A multi-dimensional array is also an object.

Output:

null
null
null

Each of the above casts performs narrowing reference conversion, attempting to convert from a supertype (Object) to a subtype (some array).

Notes

  1. An expression beginning with a + or - cannot be cast to a reference type, but can be cast to a primitive type. This simplifies the Java grammar but seems to be the result of a nominal oversight in the language's design. The justification for this grammar seems to be an oversight in the design of the Java language. The relevant footnote, in section 15.15, assumes that
    all type names involved in casts on numeric values are known keywords

    However, there are in fact valid reference-type casts, generic casts, and even intersection casts that can be applied to other expressions of numeric types, though none to the aforementioned unary expressions:

    	// Valid
    	System.out.println((Object) 1);
    	System.out.println((Comparable<Integer>) 1);
    	System.out.println((Object & Serializable & Comparable<Integer>) 1);
    
    	// Invalid
    //	System.out.println((Object) -1);
    //	System.out.println((Comparable<Integer>) -1);
    //	System.out.println((Object & Serializable & Comparable<Integer>) -1);

    For example,

    	System.out.println((int) +10);		// Valid
    //	System.out.println((Integer) +10);	// Invalid
    
    	int x = 10;
    	System.out.println((int) ++x);		// Valid
    //	System.out.println((Integer) ++x);	// Invalid

    This limitation can be overcome by parenthesizing the argument to the cast expression.

    	System.out.println((Integer) (+10));	// Valid
    
    	int x = 10;
    	System.out.println((Integer) (++x));	// Valid
  2. The ability to cast a lambda expression or method reference to a type parameterized with a wildcard allows creating an instance of an interface in a way that is otherwise impossible without using raw types.

    An interface can be declared generic with a type parameter bounded by a private (inaccessible) class. For example:

    class ContainerType {
    	private static class PrivateClass {	}
    
    	public interface Interface<T extends PrivateClass> {
    		int doSomething();
    	}
    }

    Classes outside of ContainerType can refer to Interface but not use it as a type unless using it raw or with the ? wildcard type argument. The only other permissible parameterization is PrivateClass which is inaccessible.

    In a separate class, one can instantiate Interface using a lambda expression or method reference without using Interface as a raw type and without having to refer to PrivateClass (which would raise a compile-time error) using a wildcard:

    public class Example {
    	public static void main(String[] args) {
    		Object x = (Interface<?>) () -> 1;
    	}
    }

    Because of the cast, the lambda expression is instantiated as the type Interface<PrivateClass> due to capture conversion. This becomes the type of the lambda expression itself. Since PrivateClass is not explicitly referenced, no compile-time error occurs. The cast expression converts the type to Interface<?>, which is the result of the cast expression itself.