skip to content

What is a widening primitive conversion in Java, and why does it happen automatically?

level: juniorimportance: must knowfreq 62%

answer

  1. Smaller range -> bigger range, no cast
  2. byte short int long float double; char into int and up
  3. Magnitude always safe; exactness not (int/long -> float/double)
  4. char is unsigned, widens to int+

basics

~20 s

Widening turns a smaller numeric type into a bigger one, like int to long or int to double. Java does it automatically because the bigger type can always hold the value, so no data is lost.

solid answer

~40 s

A widening primitive conversion converts a value to a type with a larger (or at least equal) range, such as int to long, long to float, or int to double. Java performs it implicitly (no cast needed) because the target type can represent every value of the source type, so the conversion is considered safe. The defined widening paths are byte to short to int to long to float to double, plus char to int and up. There is one subtlety: int to float and long to float/double can lose precision because floating-point types have limited significant bits, even though magnitude is preserved. Magnitude is never lost, but exactness can be for very large integer values converted to float or double.

go deeper

for a junior

Knows widening goes small-to-big and is automatic, and can name examples like int to long and int to double.

for a middle

Knows the full widening order, that char widens to int, and that int/long to float/double can lose precision despite being widening.

for a senior

Can explain the mantissa/precision reason behind floating-point precision loss and reason about exact bit counts (24 vs 32, 53 vs 64).

for a principal

Frames it in terms of JLS-defined conversion contexts and can discuss API design implications (e.g. avoiding silent precision loss in numeric pipelines).

## What "primitive" and "conversion" mean Java has eight **primitive types** built into the language: `byte`, `short`, `int`, `long`, `float`, `double`, `char`, and `boolean`. The first six are numeric. Each numeric type has a fixed size in memory and therefore a fixed **range** of values it can hold: | Type | Size (bits) | Approx. range | |------|------|------| | `byte` | 8 | -128 to 127 | | `short` | 16 | -32,768 to 32,767 | | `char` | 16 | 0 to 65,535 (unsigned) | | `int` | 32 | about +/- 2.1 billion | | `long` | 64 | about +/- 9.2 quintillion | | `float` | 32 | huge range, ~7 decimal digits of precision | | `double` | 64 | huge range, ~15 decimal digits of precision | A **conversion** means taking a value of one type and producing an equivalent value of another type. ## What widening is A **widening primitive conversion** moves a value from a type with a *smaller* range to a type with a *larger or equal* range. The Java Language Specification defines exactly these widening paths: - `byte` -> `short` -> `int` -> `long` -> `float` -> `double` - `char` -> `int` -> `long` -> `float` -> `double` Because the destination can hold everything the source can hold, the compiler lets you do this **implicitly** -- you do **not** write a cast. Example: ```java int i = 100; long l = i; // int -> long, automatic double d = l; // long -> double, automatic ``` ## Why it is automatic / safe "Safe" here means **the magnitude of the number is always preserved** -- you never get a wildly wrong value. Since the target range fully contains the source range, the number always fits. ## The one caveat: precision vs. magnitude There is an important subtlety. `float` and `double` store numbers as a sign, a fraction (mantissa), and an exponent -- they trade exactness for range. A `float` has only about 24 bits of precision, and a `double` about 53 bits. So: - `int` -> `float`: an `int` has 32 bits of precision, but `float` has only ~24. A large `int` can lose its least-significant digits. - `long` -> `float` and `long` -> `double`: a `long` has 64 bits, more than either floating type's precision, so big `long` values can become approximate. ```java int big = 123_456_789; float f = big; // widening, but... System.out.println((int) f); // 123456792 -- not equal! precision lost ``` So widening **never changes the magnitude** (the value stays roughly the same size), but for these integer-to-floating cases it **can lose precision** (exactness). This is the only data-loss possible in widening, and the language permits it implicitly anyway. ## Special note on char `char` is unsigned (0 to 65,535). It widens to `int` and above by taking its numeric code-point value. It does **not** widen to `byte` or `short`, because those are signed and smaller -- that direction would be narrowing.

  • Does int to float ever lose data, even though it is a widening conversion?
    Yes. float has only ~24 bits of precision while int has 32, so large int values can lose their lowest digits. Magnitude is preserved but exactness is not.
  • Why does char widen to int but not to short?
    char is 16-bit unsigned (0..65535); short is 16-bit signed (max 32767). short cannot hold the upper half of char's range, so that direction is narrowing, not widening. int can hold all char values, so char->int is widening.

saying these in an interview costs you the question

  • Claiming widening can never lose any information (int/long to float/double can lose precision)
  • Thinking a cast is needed for widening
  • Believing char widens to byte or short

context