skip to content

Primitive Types

byte, short, int, long, float, double, char and boolean, each with a fixed size and range independent of platform. Being able to state the ranges — and that char is an unsigned 16-bit value — is standard screening material.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

6

What are the default values of primitive fields, and when do defaults apply versus when must you initialize?

level: juniorimportance: must knowfreq 55%

answer

  1. Fields auto-default: numbers 0, char '', boolean false
  2. Local variables get NO default -> compile error if read first
  3. Array elements default like fields (0 / false / '')
  4. Primitives never null; wrapper fields (Integer) default to null -> NPE risk
  5. 'definite assignment' is a compile-time check

basics

~10 s

Uninitialized primitive fields get defaults: 0 for numbers, 0.0 for float/double, '' for char, false for boolean. Local variables get NO default — you must assign before use or the code won't compile.

solid answer

~40 s

Primitive instance and static fields are automatically initialized to a 'zero' default if you don't assign one: numeric types (byte, short, int, long) to 0, float to 0.0f, double to 0.0, char to '' (numeric 0), and boolean to false. Array elements get the same defaults when the array is allocated. The crucial exception is **local variables** (declared inside a method): they receive *no* default, and the compiler enforces 'definite assignment' — reading one before it is assigned is a compile error, not a runtime surprise. This is a deliberate safety feature. Primitives can never be null, so unlike reference types there is no NullPointerException risk from an uninitialized primitive field; instead you risk silently using a 0 or false you didn't intend.

code

java · 16 lines
java
class Box {
    int n;          // -> 0
    double d;       // -> 0.0
    boolean flag;   // -> false
    char c;         // -> ''
}

void demo() {
    int local;
    // System.out.println(local); // COMPILE ERROR: might not be initialized
    local = 5;
    System.out.println(local);    // 5

    int[] arr = new int[3];
    System.out.println(arr[0]);   // 0 (array elements get field-style defaults)
}

go deeper

for a junior

Knows the default-value table and that local variables must be initialized before use.

for a middle

Explains definite-assignment analysis, that array elements default like fields, and the int-vs-Integer null distinction.

for a senior

Articulates why the field/local distinction exists, blank-final rules, and the NPE risk from auto-unboxing null wrappers.

for a principal

Sets conventions to avoid silent-default bugs (e.g. preferring explicit initialization, validating constructed state) and reasons about null-safety strategy across primitive/wrapper boundaries.

## Two categories of variables Where a variable lives determines whether it gets a default value: 1. **Fields** — variables declared directly in a class. These are *instance fields* (one per object) or *static fields* (one per class). Also array elements. 2. **Local variables** — variables declared inside a method, constructor, or block. ## Field defaults (automatic) When an object is created (or a class is loaded, for static fields), the JVM **zero-initializes** every field before any constructor code runs. Each primitive gets its 'zero' value: | Type | Default | |------|---------| | byte, short, int, long | 0 | | float | 0.0f | | double | 0.0 | | char | '' (numeric 0) | | boolean | false | (Reference-type fields default to `null`, but that is a separate family.) **Array elements** follow the same table: `new int[3]` is `{0,0,0}`, `new boolean[2]` is `{false,false}`. So this compiles and prints `0` and `false`: ```java class Counter { int count; // default 0 boolean active; // default false } ``` ## Local variables: NO default Local variables are the important exception. They are **not** auto-initialized. Instead the Java compiler performs **definite assignment analysis**: it proves that every local variable is assigned a value on *every* path before it is read. If it cannot prove that, the program **fails to compile**: ```java int x; System.out.println(x); // COMPILE ERROR: variable x might not have been initialized ``` This is a deliberate design choice — it turns a whole class of 'used uninitialized memory' bugs (common in C) into compile-time errors. ## Why this distinction matters - **Fields** can be safely read immediately because their default is guaranteed. The risk is *semantic*: a forgotten initialization silently leaves a 0 or false that the program treats as meaningful (e.g. a price of 0). - **Locals** force you to be explicit, catching the mistake at compile time. - Because primitives are never `null`, an uninitialized primitive field never throws `NullPointerException` — but a *boxed* wrapper field (`Integer`, `Boolean`) defaults to `null` and *will* NPE if auto-unboxed. That is a frequent real bug: `Integer count;` defaults to null, and `int n = count;` throws NPE. ## blank finals A `final` field with no initializer (a 'blank final') does **not** get the zero default treatment for the purpose of the rules — it must be definitely assigned exactly once in every constructor, or the class won't compile.

  • What is the default of an Integer field versus an int field?
    An int field defaults to 0; an Integer field (a wrapper reference type) defaults to null, which will throw NullPointerException if auto-unboxed into an int.
  • Why are local variables treated differently from fields?
    The compiler enforces definite assignment for locals to catch use-before-assign bugs at compile time; fields are zero-initialized by the JVM because they can be touched from many places and a guaranteed default is safer.

saying these in an interview costs you the question

  • Thinking local variables default to 0 like fields (they don't — it's a compile error)
  • Saying an uninitialized int field is null (primitives are never null; it's 0)
  • Confusing an int field (defaults 0) with an Integer field (defaults null, can NPE on unboxing)
  • Assuming array elements are uninitialized garbage like in C

context

open as a page

What are the eight primitive types in Java, and what is the size of each?

level: juniorimportance: must knowfreq 85%

basics

~10 s

Java has eight primitives: byte (8 bits), short (16), int (32), long (64), float (32), double (64), char (16), and boolean. They hold simple values directly, not objects.

open as a page

Why does 0.1 + 0.2 not equal 0.3 with float/double, and what should you use for money?

level: middleimportance: must knowfreq 70%

basics

~10 s

float and double store numbers in binary (base 2), and many decimals like 0.1 can't be represented exactly, so tiny rounding errors creep in. For money, use BigDecimal or integer cents, not double.

open as a page

How is char different from the other primitive types in Java?

level: juniorimportance: should knowfreq 45%

basics

~10 s

char is a 16-bit unsigned number holding one UTF-16 character code (0 to 65535). It is the only unsigned primitive, and you can do arithmetic on it because it is numeric under the hood.

open as a page

What happens when an int arithmetic operation exceeds its range, and how do you detect or avoid it?

level: middleimportance: should knowfreq 60%

basics

~10 s

The value silently wraps around: adding 1 to the maximum int (2147483647) gives the minimum int (-2147483648). Java does not throw an error. Use a long, or Math.addExact to throw on overflow.

open as a page

Explain widening and narrowing conversions between primitive types and when casts are required.

level: middleimportance: should knowfreq 50%

basics

~20 s

Widening (small to big, like int to long) happens automatically because no data is lost. Narrowing (big to small, like long to int) can lose data, so Java forces you to write an explicit cast.

open as a page