JAVA / VARIABLES, PRIMITIVES AND TYPES
int, long and silent widening between them
Assign int to long without a cast, force 64-bit arithmetic with an L suffix or cast, and spot expressions that wrap before they are widened.
What you will learn
- Assign an int to a long with no cast, and explain why that conversion is always exact.
- Force 64-bit math by making one operand long: (long) count * size, or 1000L * 60.
- Spot expressions that overflow in int before the widening to long ever happens.
- Add L to integer literals above 2147483647 to avoid 'integer number too large'.
Understanding int, long and silent widening between them
An int occupies 32 bits and a long occupies 64, both signed two's complement. Because every 32-bit value has an exact 64-bit counterpart, converting int to long can never fail or lose information, so Java performs it implicitly wherever a long is expected; that implicit conversion is what widening means. At the bit level the sign bit is copied into the upper 32 bits, which is why an int -1 becomes a long -1 and not 4294967295.
The surprising part is when the widening happens. An assignment converts the value the right-hand side has already produced, so long total = a + b; with two int variables performs a 32-bit addition first and widens the result second, wrapped or not. Java computes in 64 bits only when at least one operand of that particular operator is already long, a rule called binary numeric promotion, and it is applied to each operator independently. Getting a correct long result therefore means changing an operand, not the destination variable.
Literals follow the same inside-out logic: an integer literal with no suffix has type int regardless of what it is assigned to. That is why long ns = 5_000_000_000; is rejected at compile time with 'integer number too large' — the literal itself is out of int range before the assignment is even considered. Writing 5_000_000_000L types the literal as long, and since * is left-associative, putting the L on the leftmost factor promotes every multiplication that follows it. Putting the suffix at the end of a chain sometimes appears to work, but only when the intermediate int products happen to stay under 2147483647.
public class Widening {
public static void main(String[] args) {
int seconds = 2_000_000_000;
long copied = seconds; // int -> long, no cast needed
long wrapped = seconds + seconds; // int + int in 32 bits, then widened
long kept = seconds + (long) seconds; // one long operand -> 64-bit add
System.out.println("copied = " + copied);
System.out.println("wrapped = " + wrapped);
System.out.println("kept = " + kept);
System.out.println("int max = " + Integer.MAX_VALUE);
System.out.println("long max = " + Long.MAX_VALUE);
}
}int to long widening is implicit and exact, but it converts the result of an expression, so the arithmetic inside that expression stays 32-bit unless one of its operands is a long.
Worked examples
Where the L belongs in a chain
Shows that the suffix position decides whether the multiplications run in 32 or 64 bits.
public class MillisPerMonth {
public static void main(String[] args) {
long allInt = 1000 * 60 * 60 * 24 * 30;
long firstLong = 1000L * 60 * 60 * 24 * 30;
long lastLong = 1000 * 60 * 60 * 24 * 30L;
// long literal = 2592000000; // does not compile: integer number too large
System.out.println(allInt);
System.out.println(firstLong);
System.out.println(lastLong);
}
}Example explained
Line 1allInt does four int multiplications; the last one needs 2592000000, which does not fit in 32 bits, so it wraps to -1702967296 and only then gets widened.
Line 2firstLong makes the leftmost product a long, so each remaining int operand is promoted and all four multiplications happen in 64 bits.
Line 3lastLong gives the right answer only by luck: the intermediate int product 86400000 still fits, so nothing has wrapped by the time 30L forces 64-bit math.
Line 4The commented line fails at compile time because 2592000000 is an int literal out of range; the long on the left never gets a say.
Widening decides which overload runs
Demonstrates that overload selection uses the static type of the argument, with widening as a fallback.
public class Promotion {
static void show(int v) { System.out.println("chose int: " + v); }
static void show(long v) { System.out.println("chose long: " + v); }
public static void main(String[] args) {
show(42);
show(42L);
int i = 42;
long l = 42;
show(i);
show(l);
}
}Example explained
Line 1show(42) picks the int method because an unsuffixed literal has type int, and an exact match is preferred over a widening conversion.
Line 2show(42L) picks the long method: the suffix changes the argument's type, not its value.
Line 3long l = 42; compiles even though the literal is an int, because the assignment applies the widening conversion once, at that point.
Line 4show(l) picks the long method purely from l's declared type; the small value it holds is irrelevant to the choice.
Important notes
Widening is only guaranteed exact for int to long. long to float and long to double are also implicit but can round, since a double keeps just 53 significant bits.
long buys range up to 9223372036854775807, not immunity: Java has no unsigned long, and a long counter can still overflow, roughly 2^32 times later than an int one.
Common mistakes
Fixing an overflow by widening only the variable: long ms = 1000 * 60 * 60 * 24 * 30; compiles, runs, and silently stores -1702967296 because the multiplication was never changed.
Casting the whole expression instead of an operand: long total = (long) (count * size); widens a value that already wrapped in int, so the cast just preserves the wrong number.
Reading 'integer number too large' as a complaint about the long variable and trying casts; the literal is the problem, so write 9_999_999_999L.
Try it yourself
Change, predict, then run
Declare int fileSize = 1_500_000_000; then print the total for three files twice, once as long total = fileSize * 3; and once with the multiplication forced into 64 bits, and work out where the first number came from.
Open the Java workspaceCheck your understanding
Given int a = 2_000_000_000;, which line stores 4000000000 in x?
- long x = a + a;
- long x = (long) (a + a);
- long x = (long) a + a;
- long x = Long.valueOf(a + a);
Show answer
Casting one operand makes the addition itself a 64-bit operation, because the other int operand is promoted to long before the add runs. (long) (a + a) is tempting but too late: the int addition has already wrapped to -294967296, and widening a wrapped result cannot recover the lost bits. Long.valueOf(a + a) has the same problem, since its argument is that same wrapped int.