# casting

integer casting

Some casting situations:

int x = 4096L;  This is illegal. It requires an int downward cast like int x = (int) 4096L;

short sh = (short) 32800;  This is over the 32,767 limit for short.  It compiles but you get garbage with a negative leading bit.

byte b = 0;

b += 9;  This works, as b receives implicit int casting.  See widening rules

byte b = 0;

b = b + 9;   The b = b + 9 is loss of precision as the 9 is an int, so it needs an explicit cast with complete enclosing parens.  i.e. b = ( byte ) ( b+9 );

Narrowing primitive conversions simply lop off the appropriate number of lead bits.  The sign can change.  i.e.

int x = 129;

byte b = ( byte ) x;  Here b becomes -127, not 129 as expected, because the bit in x which corresponds to b's sign happened to be on.

Upward conversions (like byte to char) always require explicit casts. i.e.

byte b = 0;

char c = '0';

Here both  b = c;  and  c = b;  would require casts

You cannot convert a char (16 bit unsigned) to a short (also 16 bit) without explicit (short) casting. i.e.

short sh = 0;

char c = '0';

Here you need  sh = ( short ) c;  and  c = ( char ) sh;  to make the assignments.

When going from char (16 bit unsigned) to short (16 bit signed), the short takes on the char’s lead bit as its sign.  i.e.

char c = 0x8001;

short sh = ( short ) c;  sh is then negative, -32767, because its lead bit was on.

floating point casting

The default for floating point is double.  i.e.

float f = 2.0; requires explicit casting to float or f.

float f = 2.0f;  works.

float f = ( float ) 2.0;  works.

object casting and binding

Objects retain their real identity (from the right hand side) after creation casting.  i.e.

Object Obj = new Float( 1 );

Float F = new Float( 2 );

if ( Obj.equals( F ) ) uses the equals(...) method from the Float class, not Object's version.

Method references are resolved at run time, using the object's actual type (again taken from the right hand side). Variable references are resolved at compile time, using the object's declared type from the left.

The following example illustrates how you can change which runtime go( ) method is selected by casting object B.  But such (run time) casting cannot change which (compile time) variable s is selected for printing.  Boat's version of s is always used.  The program prints:

Sub's go( )

Sub's go( )

Boat's s

public class RunTime {

public static void main(String[ ] args) {

Boat B = new Sub( );            // B gets its runtime type here from the right, its declared type from the left

Sub S = new Sub( );

B.go( );                                   // here B's runtime type via casting is used to find the method

S.go( );

B = S;                                     // this statement has no effect on method or variable selection

System.out.println( B.s );    // here B's compile time declared type (Boat) is used to find the variable

}

}

. . . .

class Boat {

String s = "Boat's s";

public void go( ) {

System.out.println( "Boat's go( )" );

}

}

class Sub extends Boat {

String s = "Sub's s";

public void go( ) {

System.out.println( "Sub's go( )" );

}

}

Object assignment casting tells the compiler to ignore it until run time.  But even then the cast still can’t go up the object hierarchy.  No narrowing object casting is allowed to presumably "smaller" objects up the hierarchy.  i.e.

Baseclass B = new Baseclass( );

Subclass S = ( Subclass ) B;  will compile but will give a runtime error because you don’t know what’s extra in Subclass, which is presumably larger than Baseclass. So B can’t be presumed to provide it.

Saying  S = B;  with no cast to Subclass, will not even compile.

null objects are not immune from the no downward casting rule. i.e.

Object o = null;

String s = null;

s = o;                       will not compile, as you can’t assign upwards without a cast.

s = ( String ) o;              works here.

You cannot cast null to anything.