Type casting
In the previous lesson, the average of two whole numbers came out as 2.0, not 2.5. To fix that, you need to know how Java turns a number of one type into another.
Java's calculator remembers the type of every number, and a type is like a box of a certain shape. A long box has more room than an int box, and an int box has no compartment for a fractional part. A number can always move from a small box into a bigger one. Moving it from a big box into a smaller one may mean cutting something off, and Java wants you to confirm that explicitly:
public class Main {
public static void main(String[] args) {
int count = 3;
long big = count;
double price = 4.75;
int whole = (int) price;
System.out.println(big); // 3
System.out.println(whole); // 4
}
}Let's walk through the program line by line:
long big = count;puts anintinto alongbox. The box is bigger, and Java moves the number on its own.int whole = (int) price;puts adoubleinto anintbox. There is no room for the fractional part, so(int)stands before the value: that is how you allow it to be cut off.System.out.println(big)prints3: the number did not change.System.out.println(whole)prints4: only the whole part of4.75is left.
The box picture is off in one respect: the number is not moved but copied. After (int) price, the variable price still holds 4.75.
Widening happens on its own
A widening conversion turns a value into a type with a wider range. For the numbers in this theme, the chain is int → long → double.
- Java does it on its own: in an assignment, as in
long big = count;, and in calculations. - The number stays the same:
3in alongis3, and in adoubleit is3.0.
When an int and a double meet in one expression, Java first widens the int to a double and only then calculates. The result is a double too: 3 * 2.5 is 7.5, and 7 / 2.0 is 3.5.
Narrowing only on request
A narrowing conversion turns a value into a type with a narrower range: double to int, long to int. Part of the number may be lost, so Java never narrows on its own:
double price = 4.75;
int whole = price; // ✗error: incompatible types: possible lossy conversion from double to intThe compiler refuses to put a double into an int: such a conversion may lose data. To make it agree, you need a cast, the name of the target type in parentheses before the value: int whole = (int) price;. That way you tell the compiler: "I know part of the number may be lost, and I accept it."
From double to int
The fractional part is dropped, not rounded, the same as in integer division:
(int) 4.75is4, although4.75is closer to five;(int) -4.75is-4: the result moves toward zero.
From long to int
This is narrowing too: a long holds numbers that an int cannot. Without (int), the compiler answers with the same error, only with the words from long to int. If the value fits in an int, the cast does not change it.
A cast inside an expression
A cast applies only to the value right after the parentheses. That is how you get fractional division out of two int values:
int total = 5;
int count = 2;
System.out.println((double) total / count); // 2.5
System.out.println(count * 2.5); // 5.0(double) totalturns5into5.0. The variabletotalitself stays anint.- Next,
5.0 / countis an expression with anintand adouble. Java widenscountto adouble, the division becomes fractional, and the result is2.5. count * 2.5prints5.0: the result has the typedouble, even though it is a whole number.
That is how you get the right average: 2.5 instead of 2.0.
Common mistake
The parentheses go around the whole division:
public class Main {
public static void main(String[] args) {
int total = 5;
int count = 2;
double average = (double) (total / count); // ✗
System.out.println(average); // 2.0
}
}The program prints 2.0. The parentheses made Java run total / count as integer division first and get 2. Only then did the cast turn 2 into 2.0, and the fraction was gone before that. Cast one of the numbers, not the result: (double) total / count.
Key points
- Widening (
int→long→double) happens on its own, with no cast. - Narrowing (
doubletoint,longtoint) needs a cast: without(int)the code does not compile. (int)drops the fractional part without rounding:(int) 4.75is4.- A cast applies to the nearest value:
(double) total / countgives2.5, while(double) (total / count)gives2.0.