Casting
What is Casting?
- Casting is when we take one variable type and make it look like another variable type temporarily.
Usually we do this so that an assignment can be made correctly. In order to cast we place the type
within parenthesis before whatever we are casting, (type). When casting is used there are two cases
that can occur, either widening or narrowing.
Object Casting
- An object reference can be assigned to a distinct object variable if the object reference and the
object variable type are related within the inheritance hierarchy. Here are the different possible
assignments, the rules pertaining to each, and an example code fragment.
- Unrelated Objects
- An object reference cannot be assigned to an unrelated object variable type. The example assignment
given here is invalid.
objectVariable = unrelatedObjectReference;
- Even when we attempt adding an explicit cast, this assignment is still invalid.
objectVariable = (ObjectVariableType) unrelatedObjectReference;
- Implicit Casting (Inheritance - will be covered soon)
- When we assign a subclass object reference to a superclass object variable type, the cast is
implicit, meaning the cast will occur automatically, whether explicitly listed or not.
Here is an example showing the implicit cast.
superclassVariable = subclassObjectReference;
- Here is an example showing the unnecessary explicit cast.
superclassVariable = (SuperclassVariableType) subclassObjectReference;
- Explicit Casting (Inheritance - will be covered soon)
- When a superclass variable references a subclass object, the subclass object reference can be
extracted and assigned to a subclass variable. This assignment requires an explicit
cast and cannot be made otherwise. Here is an example showing the explicit cast.
subclassVariable = (SubclassVariableType) superclassVariableContainingASubclassObjectReference;
- This example is invalid, since the explicit cast must be listed.
subclassVariable = superclassVariableContainingASubclassObjectReference;
Primitive Type: Widening
- Widening is when we assign a smaller bit size value to a larger bit size variable.
- In this case we do not need a cast because a byte is 8 bits and an int is 32 bits. We are widening
the number of bits, from 8 to 32. No information will be lost in this transfer.
byte bits = 3;
// the cast is implicit
int number = bits;
- In this case we do not need a cast because a float is 32 bits and a double is 64 bits. We are
widening the number of bits, from 32 to 64. No information will be lost in this transfer.
float value = 3.14F;
double decimal = value;
- In this case we do not need a cast because an int is 32 bits and a float is 32 bits. Although we are not widening the number of
bits, 32 to 32, we will not lost any information in this transfer. An int does not store the precision that a float does,
therefore extra precision will be added not taked away, maintaining the same level of information.
int number = 5;
float value = number;
Primitive Type: Narrowing
- Narrowing is when we assign a larger bit size value to a smaller bit size variable.
- In this example we need a cast because an int is 32 bits and a byte is 8 bits. Information will be lost, therefore we must 'cast'
or tell the compiler we are aware that information might be lost, but we want to do this anyway. As we show below, 32 bits will
not fit into 8 bits. Instead, reading from left to right, the right most 8 bits will be kept and any information in the preceding
24 bits will be lost.
int number = 10; // (0 ..... 0) 32 0's or 1's
byte bits = (byte) number; // (0 .. 0) 8 0's or 1's
- Similarly, if wanted to assign a literal int to a byte, a cast is necessary if information can be lost. Consider this assignment:
byte bits = 300;
- The assignment will not compile (try it) because 300 is not within the range of a byte. A cast can be included to force the
assignment, however note that information will be lost, 300 cannot be represented by a byte. Try using the following statement, to
see that the compilation is successful, then print the value within the variable to see the result of the lost precision.
byte bits = (byte) 300;
- In this example we need a cast because a float is 32 bits and a double is 64 bits. Information will be lost, therefore we must
'cast' or tell the compiler we are aware that information might be lost, but we want to do this anyway.
double decimal = 3.14;
float value = (float) decimal;
- In this example we need a cast because a float is 32 bits and a decimal literal is 64 bits, unless we specify the literal to be
float by placing an 'F' or 'f' after the literal. Information will be lost, therefore we must 'cast' or tell the compiler we are
aware that information might be lost, but we want to do this anyway.
float value = (float) 3.14;
OR
float value = 3.14F;
- In this example we need a cast because a int is 32 bits and a float is 32 bits, however the are stored in a different manner inside
the computer. The float has extra or more detailed information, namely the decimal places/values. Information will be lost,
therefore we must 'cast' or tell the compiler we are aware that information might be lost, but we want to do this anyway.
float value = 3.14F;
int number = (int) value;