Java Variables
A variable is a named location in memory that holds a value. Java variables come in three flavours: local variables inside methods, instance fields on objects, and class fields shared by all instances of a class. This tutorial focuses on local variables and instance fields; static fields get their full treatment in the classes tutorial.
Java is statically typed, which means every variable has a type known at compile time. The compiler uses that type to prevent you from assigning a String to an int, or calling a method that does not exist. This early error checking is the single biggest reason Java programs are stable in production: many bugs are caught by the compiler before they ever run.
1. Declaring and Initialising
To declare a variable, write the type followed by the name:
int age;
double price;
boolean isReady;
String name;
To initialise it, use the assignment operator =:
age = class="tok-num">30;
price = class="tok-num">19.99;
isReady = true;
name = "Alice";
You can combine declaration and initialisation on one line, which is the common form:
int age = class="tok-num">30;
double price = class="tok-num">19.99;
boolean isReady = true;
String name = "Alice";
class=class="tok-str">"tok-cmt">// type inference with var (Java class="tok-num">10+)
var city = "Toronto"; class=class="tok-str">"tok-cmt">// String
var count = class="tok-num">42; class=class="tok-str">"tok-cmt">// int
var pi = class="tok-num">3.14159; class=class="tok-str">"tok-cmt">// double
Java 10 introduced var for local variables, which lets the compiler infer the type from the right-hand side. Use it when the type is obvious from the initialiser — var name = "Alice"; — and avoid it when the type is not obvious, e.g. var result = service.compute(); benefits from an explicit type for the reader.
2. Variable Types
Every variable has either a primitive type (one of the eight built-in) or a reference type (a class, interface, array or record). The difference matters when you assign or pass them:
- Primitive variables hold the value directly. Assigning
b = acopies the value. - Reference variables hold a reference (an address) to an object. Assigning
b = acopies the reference, so both variables now point to the same object.
class=class="tok-str">"tok-cmt">// primitive: copy the value
int a = class="tok-num">10;
int b = a; class=class="tok-str">"tok-cmt">// b now has its own copy of class="tok-num">10
b = class="tok-num">20; class=class="tok-str">"tok-cmt">// a is still class="tok-num">10
class=class="tok-str">"tok-cmt">// reference: copy the reference
int[] x = {class="tok-num">1, class="tok-num">2, class="tok-num">3};
int[] y = x; class=class="tok-str">"tok-cmt">// y now points to the same array as x
y[class="tok-num">0] = class="tok-num">99; class=class="tok-str">"tok-cmt">// x[class="tok-num">0] is also class="tok-num">99 now
This distinction is the source of almost every “why did my object change?” question in early Java. Draw it on paper until it is intuitive.
3. Scope and Lifetime
A variable's scope is the region of code where the name is visible. Java scopes are lexical: a variable declared inside a block is visible only inside that block (and any nested block).
public class Scope {
public static void main(String[] args) {
int outer = class="tok-num">1; class=class="tok-str">"tok-cmt">// visible until end of main
if (outer == class="tok-num">1) {
int inner = class="tok-num">2; class=class="tok-str">"tok-cmt">// visible only inside this block
System.out.println(outer + inner); class=class="tok-str">"tok-cmt">// OK
}
class=class="tok-str">"tok-cmt">// System.out.println(inner); // compile error: inner not visible
}
}
Once the closing brace of the declaring block is reached, the variable is no longer accessible. The garbage collector may later reclaim the object it referred to, if nothing else references it.
4. Naming Conventions and Rules
Java variable names must:
- Start with a letter, underscore, or dollar sign.
- Contain only letters, digits, underscores or dollar signs thereafter.
- Not be a Java keyword (
class,int,return, …).
By convention, variable names use lowerCamelCase: firstName, orderId, maxRetries. Constants — final variables that never change — use UPPER_SNAKE_CASE: MAX_RETRIES, DEFAULT_PAGE_SIZE.
5. The final Keyword
Adding final to a declaration means the variable can be assigned exactly once. After that, any further assignment is a compile-time error:
final int maxUsers = class="tok-num">100;
maxUsers = class="tok-num">200; class=class="tok-str">"tok-cmt">// compile error: cannot assign twice
final StringBuilder sb = new StringBuilder("hi");
sb.append("!"); class=class="tok-str">"tok-cmt">// OK - we are mutating the object, not the variable
class=class="tok-str">"tok-cmt">// sb = new StringBuilder(); // compile error: would reassign the reference
Use final liberally for local variables. It documents intent — “this value does not change” — and the compiler will catch accidental reassignments. Many teams adopt the rule “final by default” for locals and parameters, removing final only when reassignment is genuinely needed.
6. Instance Fields
Variables declared inside a class but outside any method are fields. Without static, they are instance fields: one copy per object. Every time you create an object with new, the JVM allocates fresh storage for each instance field.
public class BankAccount {
class=class="tok-str">"tok-cmt">// instance fields - one set per object
private String owner;
private double balance;
public BankAccount(String owner, double opening) {
this.owner = owner;
this.balance = opening;
}
}
class=class="tok-str">"tok-cmt">// usage:
BankAccount a = new BankAccount("Alice", class="tok-num">100.0);
BankAccount b = new BankAccount("Bob", class="tok-num">250.0);
class=class="tok-str">"tok-cmt">// a and b each have their own owner and balance
Instance fields hold the state of an object. They are usually marked private so code outside the class cannot modify them directly — this is encapsulation, covered in its own tutorial.
Exercises
- Declare an
int, adouble, aboolean, and aString. Print them all withSystem.out.println. - Reproduce the reference-vs-primitive diagram above with two
StringBuilderobjects and print their values after each assignment. - Write a method with a local variable declared inside an
ifblock. Try to use it outside the block and read the compiler error. - Mark five local variables
finalin a small program. Try to reassign one of them and confirm the compiler rejects it.