Table of Contents
What is Type Casting?
- Type casting in Java is when you transform one type, class, or interface into another type, class, or interface.
- Assigning a value of one type to a variable of another type is known as Type Casting.
Without type casting, you cannot assign a value of one type to a variable of a different type.
What are the 2 Types of Type Casting?
In Java there are 2 types of Type Casting:
- Widening (Implicitly casted)
- Narrowing (Explicit casted)
Widening Type Casting involves assigning a value to a variable type that has a bigger range (small to big). This is implicitly (automatically) done by Java, so for example, Java automatically converts an integer to a floating point value. So letting Java evaluate 3 * 4.5
is the same as 3.0 * 4.5
. That’s because you can always assign a value to a numeric variable whose type supports a larger range of values, in this case the integer value is assigned to the larger-ranged floating point variable type. Another example is that you can assign a long
value to a float
variable.
Narrowing Type Casting involves assigning a value to a variable type that has a smaller range (big to small). This is explicitly (manually) done by the programmer, so for example, you need to manually convert a floating point to an integer value. Let’s say the floating point number we want to convert into an integer is 1.7 . So the Java code to do so would look something like this:
System.out.println((int)1.7);
which displays/prints 1
.
So you can see from the above example that the syntax for casting a type is to specify the target type in parentheses, followed by the variable’s name of the value to be cast.
How do I Know Which Type of Casting to use?
The ranges of the different types, from smallest to biggest:
byte < short < int < long < float < double char < int
If you choose to assign a value with a small type range to a variable with a big type range, you use widening (implicit casting automatically done by Java). i.e. byte value to short variable.
If you choose to assign a value with a big type range to a variable with a small type range, you use narrowing (requires explicit casting from the programmer). i.e. short value to byte variable.
More Examples of Type Casting
The following statement:
System.out.println((double)1/2);
displays 0.5
, because 1
is cast to 1.0
first, then 1.0
is divided by 2
.
However, the statement:
System.out.println(1/2);
displays 0
, because 1
and 2
are both integers and the resulting value should also be an integer.
Note that casting does not change the variable being cast. For example, d
is not changed after casting in the following code:
double d = 4.5; int i = (int) d; // i becomes 4, but d is still 4.5
Note that to assign a variable int
type to a variable of the short
or byte
type, explicit casting must be used. For example, the following statements have a compile error:
int i = 1; byte b = i; // Error because explicit casting is required
However, so long as the integer literal is within the permissible range of the target variable, explicit casting is not needed to assign an integer literal to a variable of the short
or byte
type.
*Be careful when using casting, as a loss of information might lead to inaccurate results (as a result of casting a value to a different type).
Where does Explicit and Implicit Casting Come From?
First, we need to understand how Magnitude & Precision related to casting.
Magnitude is how big of a range the data type can fit.
long
data types have 64-bits, and since numbers are represented using two’s complement, signed long
numbers have a valid range from -263 to 263 − 1 (that’s -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807).
float
data types only have 32-bits, but numbers are represented using IEEE 754 single floating point notation, and so float
s have a valid range of about ±3.4 * 1038, which is a lot larger than what a long
can contain.
So the magnitude of a float is larger than that of a long.
Precision is how much of a number can be represented by a data type. For example, suppose you had two variables that you wanted to use to approximate pi, an int
and a float
:
int iPi = 3; float fPi = 3.14159f;
Even though neither are really close to the actual value of pi (and no data type will ever be), fPi
is more precise than iPi
because it can hold more information regarding the number.
In IEEE 754 single floating point notation, 23 of the 32 bits are dedicated to what’s known as the “mantissa”, which is what’s used to represent the significant digits of a number. However, a long
number can be too large to completely represented in the mantissa, so the last few parts might be truncated, resulting in the float
not being the same number as the long
. You can see this demonstrated in the following example:
long a = 1234567890; float b = a; System.out.println(a - (int)b); // prints -46 instead of 0
This is because 1234567890 loses precision when stored in the mantissa of a float.
As for why you don’t need an explicit cast – it’s just a design decision the makers of Java made. They decided that operations which lose information about the magnitude require an explicit cast, while operations which lose precision don’t. [Source]
TL;DR:
1000 has bigger Magnitude(range) .1000 has bigger Precision You need use explicit casting when casting to a type that has a smaller magnitude. Otherwise, Type Casting in Java ignores precision.