skip to content

Variables

The kinds of variable Java has, where each lives, how final and shadowing affect them, and how var infers a type. Interviewers use this area to test precision about lifetime and scope.

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

explore

questions

24

What is definite assignment in Java, and why does the compiler reject reading a local variable that might be unassigned?

level: juniorimportance: must knowfreq 62%

answer

  1. Locals have no default; fields do
  2. DA = assigned on EVERY path before a read
  3. Compile-time, structural, conservative
  4. Constant expressions (true/false) are special-cased
  5. Only reads are constrained, not assignments

basics

~20 s

Definite assignment is a compile-time check that every local variable is given a value before you read it. If the compiler can find any path where the variable might not be set yet, it refuses to compile and reports a "variable might not have been initialized" error.

solid answer

~40 s

Definite assignment is a static analysis the Java compiler runs to guarantee that every local variable has a definitely-assigned value at the point it is read. Unlike fields, locals get no default value, so reading an unset local would expose garbage; the language forbids it at compile time instead. The compiler tracks, for each program point, whether a variable is "definitely assigned" along every possible execution path leading there. If any path could reach a read without an assignment, you get a compile error. This makes a whole class of uninitialized-variable bugs impossible. The analysis is conservative and path-based: it works on the structure of the code (if/else, loops, try/catch, switch), not on actual runtime values, so it can occasionally reject code that would in practice always assign.

go deeper

for a junior

Knows locals must be initialized before use and that the compiler enforces it, recognizes the "might not have been initialized" error.

for a middle

Can explain the every-path requirement, distinguishes locals from fields, and knows the check is compile-time and conservative.

for a senior

Articulates that the analysis is structural/path-based per JLS, special-cases constant expressions, and applies to blank finals; can predict when the compiler will reject seemingly-fine code.

for a principal

Frames it as a safety invariant of the type/flow system, contrasts with languages lacking it, and can discuss the trade-off between conservatism and false rejections, plus its interaction with final and exceptions.

## What problem this solves In Java a **local variable** (a variable declared inside a method, constructor, or block) does **not** receive a default value. Compare this with **fields** (variables declared at class level), which are automatically initialized to `0`, `false`, `null`, etc. If locals also silently defaulted, you could accidentally read a variable you forgot to set and get meaningless data. To prevent that entire bug category, the Java Language Specification (JLS, the official rulebook for the language) requires that a local variable be **definitely assigned** before any access that reads its value. ## What "definitely assigned" means At every point in the program, the compiler classifies a variable as either *definitely assigned* (DA) or *not*. A variable is DA at a given point if **every possible execution path** that reaches that point has already executed an assignment to it. "Every path" is the key phrase: it is not enough for *some* branch to assign the variable — *all* branches that can reach the read must. ```java int x; if (cond) { x = 1; } System.out.println(x); // ERROR: if cond is false, x is unassigned here ``` The `else` path (cond false) reaches the `println` without assigning `x`, so `x` is **not** definitely assigned there, and the compiler rejects it. ```java int x; if (cond) { x = 1; } else { x = 2; } System.out.println(x); // OK: every path assigns x ``` Now both branches assign `x`, so after the `if/else` it is definitely assigned. ## It is static and conservative The analysis runs at **compile time** and looks only at the *shape* of the code — the control-flow structure — never at the runtime values of variables. So it is **conservative**: it may reject code that, by human reasoning, would always assign the variable. ```java int x; if (true) { // a true constant: the compiler DOES special-case this x = 1; } System.out.println(x); // OK only because `true` is a constant expression ``` The compiler does evaluate **constant expressions** (`true`, `false`, `1 == 1`) when deciding reachability, but it will not reason about an ordinary boolean variable whose value it cannot know statically. ## Reading vs. assigning The rule only constrains a variable's **use as a value (a read)**. Assigning a value is always fine; declaring is fine. So: ```java int x; // declaration only — fine x = compute(); // assignment — fine int y = x; // read of x — requires x be definitely assigned (it is) ``` ## Where it applies Definite assignment governs **local variables** and **blank `final` fields/parameters** (finals with no initializer). It does **not** apply to ordinary non-final fields, because those have language-defined defaults. The rules cover all control structures — `if`, `while`, `for`, `do`, `switch`, `try/catch/finally`, the conditional operator `?:`, `&&`/`||`/`!`, `break`/`continue`/`return`/`throw` — each with its own JLS rule for how DA flows through it. ## Why it matters This check turns a common runtime mistake (using an uninitialized value) into an immediate compile-time error, with zero runtime cost. It is one of the reasons Java programs rarely exhibit the "reading garbage memory" bugs familiar from languages where locals are not checked.

  • Do fields need definite assignment too?
    Ordinary (non-final) fields don't — they get default values (0/false/null). Blank final fields and blank final locals/parameters DO require definite assignment before use, and final fields additionally require definite *unassignment* before assignment.
  • Why doesn't the compiler just default locals to 0/null like fields?
    It's a deliberate design choice: forcing explicit initialization catches "forgot to set it" bugs at compile time. A silent default would hide those bugs and make code intent ambiguous.

It's like a checklist at airport security: every passenger (every code path) must show a boarding pass (an assignment) before they reach the gate (the read). It is not enough that most passengers have one.

saying these in an interview costs you the question

  • Saying locals default to 0/null like fields — they don't, that's the whole point
  • Claiming the check inspects runtime values — it is purely static/structural
  • Thinking an assignment in just one if-branch is enough
  • Confusing definite assignment (must be set before read) with definite unassignment (final must NOT be set yet)

context

open as a page

What does the final keyword mean when applied to a local variable, and what happens if you try to reassign it?

level: juniorimportance: must knowfreq 70%

basics

~10 s

final means the variable can be assigned a value only once. After that first assignment you cannot change it. Trying to reassign it is a compile error, so the program will not even build.

open as a page

What is variable shadowing in Java, and can you give a common example?

level: juniorimportance: must knowfreq 70%

basics

~20 s

Shadowing happens when a variable in an inner scope has the same name as one in an outer scope, so the inner one hides the outer one. A classic case is a constructor parameter named the same as a field.

open as a page

What are the three kinds of variables in Java, and how do they differ in where they live and how long they exist?

level: juniorimportance: must knowfreq 85%

basics

~20 s

Local variables live inside a method and disappear when it ends. Instance variables belong to each object and live as long as the object. Static variables belong to the class itself, so there is just one copy shared by everything.

open as a page

What is `var` in Java, and what does it actually do to a local variable declaration?

level: juniorimportance: must knowfreq 70%

basics

~20 s

var lets you declare a local variable without writing its type; the compiler figures out the type from the value you assign. The variable still has a fixed type — var just saves you from typing it.

open as a page

What is the difference between a final reference and an immutable object? Can a final variable still 'change'?

level: middleimportance: must knowfreq 65%

basics

~20 s

final stops you from pointing the variable at a different object. It does not stop the object itself from changing. So a final List can still have items added to it; you just cannot replace the whole list with a new one.

open as a page

How do you declare a constant in Java with static final, and what does static add over plain final?

level: middleimportance: must knowfreq 68%

basics

~20 s

A Java constant is usually a static final field, e.g. public static final int MAX = 100;. static means one shared copy for the whole class instead of one per object, and final means it cannot be reassigned. The naming convention is ALL_CAPS_WITH_UNDERSCORES.

open as a page

How does Java decide which variable a bare name refers to when a field and a local of the same name both exist?

level: middleimportance: must knowfreq 55%

basics

~20 s

Java looks at the closest (innermost) scope first. If a local variable or parameter has the name, that wins; the field is only used if no closer variable has the name. Use this.name to force the field.

open as a page

Where can you NOT use `var`, and why are those uses disallowed?

level: middleimportance: must knowfreq 65%

basics

~20 s

You can only use var for local variables that have a value assigned right away. You cannot use it for class fields, method parameters, method return types, or a local variable declared with no initializer.

open as a page

Why can a static method not directly access instance variables, but an instance method can access static variables?

level: juniorimportance: should knowfreq 50%

basics

~20 s

A static method belongs to the class, not to any object, so it has no specific object whose instance variables it could read. An instance method already runs on an object, and since there is one shared static variable per class, it can reach that too.

open as a page

How does definite assignment interact with final variables and blank final fields?

level: middleimportance: should knowfreq 48%

basics

~20 s

A final variable can be assigned exactly once. The compiler uses two flow checks: it makes sure a final is definitely assigned before you read it, and definitely UN-assigned (not yet set) before each assignment. Together these guarantee "assigned once, never reassigned."

open as a page

What bugs can accidental variable shadowing cause, and how do you prevent or detect them?

level: middleimportance: should knowfreq 40%

basics

~10 s

Accidental shadowing makes you read or write the wrong variable, like a setter assigning a parameter to itself so the field never updates. Prevent it with this.field, clear names, and compiler warnings or linters.

open as a page

Explain variable scope in Java: what determines where a variable is visible, and what happens when names overlap (shadowing)?

level: middleimportance: should knowfreq 60%

basics

~20 s

A variable is visible only inside the block of curly braces where it is declared, plus any blocks nested inside it. If a local variable has the same name as a field, the local one wins inside that block; this is called shadowing.

open as a page

Is `var` a type at runtime? Explain what 'var is not a runtime type' means and the implications.

level: middleimportance: should knowfreq 40%

basics

~20 s

No. var is not a type. It is only a way to tell the compiler 'figure out the type for me.' After compilation the variable has a normal concrete type, exactly as if you had typed it yourself, so there is no var type anywhere at runtime.

open as a page

How does definite-assignment analysis handle loops, try/catch/finally, and statements that complete abruptly (return/throw/break)?

level: seniorimportance: should knowfreq 34%

basics

~20 s

The compiler models control flow. A loop body might run zero times, so assignments inside it usually don't count as guaranteed. A catch block could be entered after an assignment in the try only partly ran, so the try's assignments aren't trusted in catch. Code that always returns, throws, or breaks doesn't need to reach the rest, so those paths are excluded.

open as a page

How can a final instance field be initialized, and what guarantees does the compiler enforce for blank final fields?

level: seniorimportance: should knowfreq 45%

basics

~20 s

A final instance field can be set at its declaration or inside every constructor, but exactly once. The compiler checks that by the time any constructor finishes, every final field has been assigned on all paths, and never twice. This is great for required, unchanging fields.

open as a page

What does 'effectively final' mean, and why must variables captured by a lambda be final or effectively final?

level: seniorimportance: should knowfreq 60%

basics

~20 s

A local variable is effectively final if you never reassign it after its first value, even though you did not write the word final. Lambdas and anonymous classes can only use such variables, because they capture the value, not a live link to your method's variable.

open as a page

What restriction does Java place on lambdas and inner classes regarding shadowing local variables, and why?

level: seniorimportance: should knowfreq 35%

basics

~20 s

A lambda cannot declare a parameter or local with the same name as a variable already in scope in the enclosing method; that is a compile error. Anonymous and local inner classes also capture effectively-final locals and cannot redeclare them.

open as a page

How does variable shadowing differ from field hiding and from method overriding?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Shadowing is a local or parameter hiding a same-named field in one scope. Field hiding is a subclass field hiding a superclass field of the same name. Overriding is about methods and is chosen at runtime. Only overriding is polymorphic.

open as a page

What are the practical risks of using static (class) variables for mutable shared state, especially in multithreaded code?

level: seniorimportance: should knowfreq 55%

basics

~20 s

A static variable is one shared copy for the whole program. If several threads change it at once you can get wrong results, and it can cause hard-to-test code and memory leaks because it stays alive for the whole run.

open as a page

Exactly what static type does the compiler infer for a `var`? Walk through a few tricky cases.

level: seniorimportance: should knowfreq 55%

basics

~20 s

The compiler infers the type of the initializer expression. So var x = 5 is int, var s = "hi" is String, and var d = 3.0 is double. Whatever the right-hand side's type is, that becomes the variable's fixed type.

open as a page

When should you use `var` and when should you avoid it? How would you set team guidance?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Use var when the type is obvious from the right-hand side, like var user = new User();. Avoid it when the type is unclear, like var x = doSomething();, because the reader can no longer see what x is.

open as a page

In what order are static variables, instance variables, and their initializer blocks set up when a class is first used and an object is created?

level: seniorimportance: nice to knowfreq 35%

basics

~20 s

Static parts run once when the class is first loaded, top to bottom. Then, every time you create an object, the instance fields and instance blocks run top to bottom, and finally the constructor body runs.

open as a page

Definite-assignment analysis sometimes rejects code that could never actually read an unassigned variable. Why is the language designed to be conservative this way, and what are the trade-offs?

level: principalimportance: nice to knowfreq 15%

basics

~20 s

The check looks only at code structure, not at what values variables hold at runtime. Deciding the exact set of reachable states is impossible in general, so the language uses a simpler, conservative rule that may reject a few safe programs but never accepts an unsafe one. You add an explicit initializer to satisfy it.

open as a page