Casting

edit

Casting is the conversion of one type to another. Implicit casts are casts that occur automatically, such as during an assignment operation. Explicit casts are casts where you use the casting operator to explicitly convert one type to another. This is necessary during operations where the cast cannot be inferred.

To cast to a new type, precede the expression by the new type enclosed in parentheses, for example (int)x.

The following sections specify the implicit casts that can be performed and the explicit casts that are allowed. The only other permitted cast is casting a single character String to a char.

Grammar:

cast: '(' TYPE ')' expression

Numeric Casting

edit

The following table shows the allowed implicit and explicit casts between numeric types. Read the table by row. To find out if you need to explicitly cast from type A to type B, find the row for type A and scan across to the column for type B.

Explicit casts between numeric types can result in some data loss. A smaller numeric type cannot necessarily accommodate the value from a larger numeric type. You might also lose precision when casting from integer types to floating point types.

byte

short

char

int

long

float

double

byte

implicit

implicit

implicit

implicit

implicit

implicit

short

explicit

explicit

implicit

implicit

implicit

implicit

char

explicit

explicit

implicit

implicit

implicit

implicit

int

explicit

explicit

explicit

implicit

implicit

implicit

long

explicit

explicit

explicit

explicit

implicit

implicit

float

explicit

explicit

explicit

explicit

explicit

implicit

double

explicit

explicit

explicit

explicit

explicit

explicit

Example(s)

int a = 1;            // Declare int variable a and set it to the literal
                      //   value 1
long b = a;           // Declare long variable b and set it to int variable
                      //    a with an implicit cast to convert from int to long
short c = (short)b;   // Declare short variable c, explicitly cast b to a
                      //   short, and assign b to c
byte d = a;           // ERROR: Casting an int to a byte requires an explicit
                      //   cast
double e = (double)a; // Explicitly cast int variable a to a double and assign
                      //   it to the double variable e. The explicit cast is
                      //   allowed, but it is not necessary.

Reference Casting

edit

A reference type can be implicitly cast to another reference type as long as the type being cast from is a descendant of the type being cast to. A reference type can be explicitly cast to if the type being cast to is a descendant of the type being cast from.

Examples:

List x;                        // Declare List variable x
ArrayList y = new ArrayList(); // Declare ArrayList variable y and assign it a
                               //   newly allocated ArrayList [1]
x = y;                         // Assign Arraylist y to List x using an
                               //   implicit cast
y = (ArrayList)x;              // Explicitly cast List x to an ArrayList and
                               //  assign it to ArrayList y
x = (List)y;                   // Set List x to ArrayList y using an explicit
                               //   cast (the explicit cast is not necessary)
y = x;                         // ERROR: List x cannot be implicitly cast to
                               //   an ArrayList, an explicit cast is required
Map m = y;                     // ERROR: Cannot implicitly or explicitly cast [2]
                               //   an ArrayList to a Map, no relationship
                               //   exists between the two types.

[1] ArrayList is a descendant of the List type. [2] Map is unrelated to the List and ArrayList types.

def Type Casting

edit

All primitive and reference types can always be implicitly cast to def. While it is possible to explicitly cast to def, it is not necessary.

However, it is not always possible to implicitly cast a def to other primitive and reference types. An explicit cast is required if an explicit cast would normally be required between the non-def types.

Examples:

def x;          // Declare def variable x and set it to null
x = 3;          // Set the def variable x to the literal 3 with an implicit
                //   cast from int to def
double a = x;   // Declare double variable a and set it to def variable x,
                //   which contains a double
int b = x;      // ERROR: Results in a run-time error because an explicit cast is
                //   required to cast from a double to an int
int c = (int)x; // Declare int variable c, explicitly cast def variable x to an
                //   int, and assign x to c

Boxing and Unboxing

edit

Boxing is where a cast is used to convert a primitive type to its corresponding reference type. Unboxing is the reverse, converting a reference type to the corresponding primitive type.

There are two places Painless performs implicit boxing and unboxing:

  • When you call methods, Painless automatically boxes and unboxes arguments so you can specify either primitive types or their corresponding reference types.
  • When you use the def type, Painless automatically boxes and unboxes as needed when converting to and from def.

The casting operator does not support any way to explicitly box a primitive type or unbox a reference type.

If a primitive type needs to be converted to a reference type, the Painless reference type API supports methods that can do that. However, under normal circumstances this should not be necessary.

Examples:

Integer x = 1;               // ERROR: not a legal implicit cast
Integer y = (Integer)1;      // ERROR: not a legal explicit cast
int a = new Integer(1);      // ERROR: not a legal implicit cast
int b = (int)new Integer(1); // ERROR: not a legal explicit cast

Promotion

edit

Promotion is where certain operations require types to be either a minimum numerical type or for two (or more) types to be equivalent. The documentation for each operation that has these requirements includes promotion tables that describe how this is handled.

When an operation promotes a type or types, the resultant type of the operation is the promoted type. Types can be promoted to def at compile-time; however, at run-time, the resultant type will be the promotion of the types the def is representing.

Examples:

2 + 2.0     // Add the literal int 2 and the literal double 2.0. The literal
            //   2 is promoted to a double and the resulting value is a double.

def x = 1;  // Declare def variable x and set it to the literal int 1 through
            //   an implicit cast
x + 2.0F    // Add def variable x and the literal float 2.0.
            // At compile-time the types are promoted to def.
            // At run-time the types are promoted to float.