Declaring Variables

Declaring Variables

OCP Exam Topic — Understand local, instance, and class (static) variables; the var keyword; final; and effectively final. Covered in Chapter 1 of OCP Java SE 21 Developer Study Guide (Selikoff & Boyarsky).


Variable Categories

Java variables fall into three categories depending on where they are declared:

Category Declared In Lifecycle Default Value
Local Method body or block Created on entry, destroyed on exit None — must be initialized before use
Instance Class body (no static) Lives as long as the enclosing object Type-specific default (0, false, null)
Class (static) Class body with static Lives as long as the class is loaded Type-specific default
java
public class Counter { static int classCount = 0; // class variable int instanceCount = 0; // instance variable void increment() { int local = 1; // local variable instanceCount += local; classCount += local; } }

Local Variables

Local variables are declared inside a method, constructor, or block. They must be explicitly initialized before the compiler will let you read them — there is no default value.

java
void show() { int x; // System.out.println(x); // compile error: variable x might not have been initialized x = 10; System.out.println(x); // fine }

Local variables declared in a for loop initializer are scoped to the loop:

java
for (int i = 0; i < 3; i++) { System.out.println(i); } // System.out.println(i); // compile error — i is out of scope

Instance Variables

Instance variables belong to a specific object. They are initialized to their type's default when the object is constructed:

  • Numeric types → 0 (or 0L, 0.0f, 0.0)
  • boolean → false
  • char → ''
  • Reference types → null
java
public class Dog { String name; // null by default int age; // 0 by default boolean trained; // false by default }

Class (Static) Variables

A static variable is shared across all instances of a class. It is initialized once when the class is first loaded:

java
public class IdGenerator { static int nextId = 1; // shared across all instances int id = nextId++; // each new object gets the next id }

The var Keyword (Local Variable Type Inference)

Introduced in Java 10, var lets the compiler infer the type of a local variable from its initializer. It is syntactic sugar — the resulting bytecode is identical to using the explicit type.

java
var message = "Hello"; // inferred as String var count = 42; // inferred as int var items = new ArrayList<String>(); // inferred as ArrayList<String>

var Limitations — Know These for the Exam

Limitation Reason
Cannot use var without an initializer Type cannot be inferred
Cannot initialize var with null alone No type to infer
Cannot use var for instance or class fields Only allowed for local variables
Cannot use var for method parameters Explicit types required
Cannot use var in lambda parameters (without explicit types) Inference ambiguity
Cannot use var for catch parameters Not supported
java
// These all cause compile errors: var x; // no initializer var y = null; // no type inferable from null // class field: // var name = "dog"; // not allowed in field declarations // This is valid: var z = (String) null; // inferred as String (explicit cast provides the type)

var is not a reserved keyword — you can still name a variable or method var (though it's inadvisable):

java
int var = 5; // legal but confusing — var is a context-sensitive keyword

final Variables

Marking a variable final means it can be assigned exactly once. Any attempt to reassign it is a compile error.

java
final int MAX = 100; // MAX = 200; // compile error final String greeting; greeting = "Hello"; // first (and only) assignment — allowed // greeting = "Hi"; // compile error — already assigned

For reference types, final prevents reassigning the reference, not mutating the object:

java
final List<String> names = new ArrayList<>(); names.add("Alice"); // allowed — mutating the list // names = new ArrayList<>(); // compile error — reassigning the reference

Effectively Final

A variable is effectively final if it is never reassigned after its initial assignment, even without the final keyword. The compiler recognizes this property and allows such variables to be used inside lambda expressions and anonymous classes.

java
void process(String input) { String trimmed = input.trim(); // effectively final — never reassigned Runnable r = () -> System.out.println(trimmed); // allowed r.run(); }

If you later add an assignment, the variable is no longer effectively final and the lambda use becomes a compile error:

java
void broken(String input) { String trimmed = input.trim(); trimmed = trimmed.toLowerCase(); // now reassigned — no longer effectively final // Runnable r = () -> System.out.println(trimmed); // compile error }

Declaring Multiple Variables

Java allows declaring multiple variables of the same type in one statement, but each must follow the rules for that type:

java
int a = 1, b = 2, c = 3; // valid int d, e; // valid — both uninitialized locals // var f = 1, g = 2; // compile error — var allows only one declaration per statement

Key Points to Remember

  • Local variables have no default — they must be initialized before reading.
  • Instance and static variables receive defaults (0, false, null).
  • var infers a local variable's type from its initializer; it cannot be used for fields, method parameters, or with a plain null initializer.
  • final variables can be assigned only once; reference-type final variables still allow mutation of the referenced object.
  • Effectively final variables can be captured by lambdas and anonymous classes without the explicit final keyword.
  • var cannot be used in a multiple-variable declaration statement.

References