All topics
library
beginner

Primitive Types & Wrapper Classes

Know all 8 primitives, their sizes, default values, and the corresponding wrapper classes.

Eight primitives hold values directly. Each has a wrapper class that holds the same value inside an object.

Primitive = a number written on a sticky note (lightweight, no overhead). Wrapper = the same number in a sealed envelope (heavier, can be null, has methods).

Key Concepts

1
    primitive  bits   wrapper      default
    ------------------------------------------
    byte         8    Byte           0
    short       16    Short          0
    int         32    Integer        0
    long        64    Long           0L
    float       32    Float          0.0f
    double      64    Double         0.0d
    char        16    Character      '\u0000'
    boolean      -    Boolean        false
2
The difference that matters: a wrapper can be null, a primitive cannot.
    int x = null;            // will not compile
    Integer y = null;        // fine, and dangerous
3
Defaults apply to fields, not locals.
    class A {
      int count;             // 0 automatically
      void f() {
        int n;
        print(n);            // will not compile -- locals have no default
      }
    }
4
Small Integer values are cached, and this is the classic trap:
Integer
5
    Integer a = 127, b = 127;
    a == b;                  // true  -- same cached object
6
    Integer c = 128, d = 128;
    c == d;                  // false -- two objects
7
The cache covers -128 to 127. So == on wrappers appears to work until a value gets large enough, and then fails in production. Always use equals for wrappers.
==equals
8
Generics force wrappers.
    List<int> nums;          // will not compile
    List<Integer> nums;      // the only option
9
Which costs memory and time: a List<Integer> of a million values is a million objects plus a million pointers, where an int[] is one block of four megabytes.
List<Integer>int[]
10
So use the primitive streams when the volume is real:
11
    IntStream.range(0, n).sum();
12
Project Valhalla is the long-running effort to let value types close this gap. Worth knowing by name; not something to depend on yet.
13
What the interviewer is probing.1. "Integer a = 127, b = 127. Is a == b true? What about 128?" Probing: the Integer cache, which is the classic trap. Stalls: "Both true, the values are equal." Moves up: true for 127 and false for 128 — valueOf caches -128 to 127, so == compares the same object below the boundary and different objects above it.
14
2. "Why can a local int not be used before assignment, when a field can?" Probing: default values. Stalls: "Both default to zero." Moves up: fields are default-initialised to zero; locals are not, and the compiler enforces definite assignment.
15
3. "Why is List<int> illegal?" Probing: erasure and the primitive gap. Stalls: "It just is." Moves up: generics operate on reference types because of erasure, so primitives must be boxed — which is why the primitive streams exist.
16
4. "What does it cost to hold a million values in a List<Integer> rather than an int[]?" Probing: whether you can quantify the overhead. Stalls: "A bit more." Moves up: a million objects plus a million references against one contiguous block — several times the memory, and far worse cache behaviour.