In this Java fundamentals tutorial let us see about casting in Java.
This tutorial is having two parts, the first one is for casting on reference types and the second is for primitives cast.
In each part let us see about the different types of cast available and how we can use them in Java.
First we have to fix the terminologies. Java language specification (SE7-JLS-5.0) uses the word ‘conversion’ as a superset for anything and everything related to transforming objects.
The word ‘cast’ is used at places where the developer needs to explicitly tell the compiler that the instance value needs to be converted.
Attaching the cast-operator (a type between parentheses), before an object is referred as cast.
Type-safety is the mechanism provided in a programming language to ensure that there are no issues because of type mismatch between a variable and value attempted to store in it.
In Java to ensure type-safety, during compile time the compiler will check for type information between variables using the static type information available.
Then during runtime the values are checked for compatibility before storing in a variable.
As per Java language specification (SE7-JLS-5.0) conversions are broadly categorized as,
This is given for theoretical completeness. Assigning two instance of same type is identity conversion.
Integer i1;
Integer i2 = new Integer(2);
i1 = i2; //identity conversion
// cast not required, but done compiler will not complain
i1 = (Integer) i2;
These are the conversions between the primitives.
“A widening primitive conversion does not lose information about the overall magnitude of a numeric value.”
There is no cast required and will never result in a runtime exception. Following are the possible widening conversions,
class WideningConversion {
public static void main(String[] args) {
int i = 123456789;
float f = i;
}
}
“A narrowing primitive conversion may lose information about the overall magnitude of a numeric value and may also lose precision and range.” Cast required between types. Overflow and underflow may happen but a runtime exception will never happen.
Following are the possible narrowing conversions,
package com.javapapers.java;
public class NarrowingPrimitiveConversion {
public static void main(String[] args) {
float f = Float.POSITIVE_INFINITY;
long l = (long) f;
int i = (int) f;
System.out.println("long: " + l + " int: " + i);
int j = 255;
byte b = (byte) j;
// size is too large and resulted in negative
System.out.println(b);
}
}
In this section let us see about categories, widening reference conversion and narrowing reference conversion.
With respect to classes and objects, there are four categories to understand for casting.
public class JavaCast {
public static void main(String... args) {
Integer integer = new Integer(10);
Float floatt = new Float(20F);
//this is not a cast - error
// integer = floatt; //compiler error - incompatible types
// integer = (Integer) floatt;//compiler error - inconvertible types
//upcast - widening conversion
Object obj = integer; //no explicit cast required
System.out.println(obj);
//downcast - narrowing conversion
Integer in = (Integer)obj;//only subtype
System.out.println(in);
//downcast - Object to String
//runtime issue - instance Object is not of String
String str = (String)obj;//ClassCastException
}
}
Converting from a primitive type to its corresponding reference type is boxing conversion and vice versa is unboxing conversion.
Examples are,
int i = 10;
Integer iObj = new Integer(100);
iObj = i;//boxing conversion
i = iObj;//unboxing conversion
String conversion applies only to the ‘+’ operator, when one operand is a String and another is a primitive type.
In such a case, primitive type is converted to its corresponding reference type and then it is converted using the toString() method.
No cast is required.
int i = 10;
String str1 = "";
String str2 = str1 + i; //string conversion
Unchecked and Capture Conversion will be discussed in the next tutorial as part of the generics series.