Skip to content

Java Variable Types

A variable provides named storage that programs can manipulate. In Java, every variable has a specific type, which determines:

  • The size and layout of the variable’s memory.
  • The range of values that can be stored.
  • The set of operations that can be applied to it.

All variables must be declared before they are used. The basic syntax is:

dataType variableName [= initialValue];
// Or declare multiple of the same type:
dataType var1 [= val1], var2 [= val2], ...;
int count; // Declare an integer variable named count
double price = 99.95; // Declare and initialize a double
String name = "Alice"; // Declare and initialize a String object
boolean isActive = true; // Declare and initialize a boolean
char grade = 'A'; // Declare and initialize a character

Java has three main kinds of variables based on their scope and lifetime:

  • Local Variables
  • Instance Variables (Non-Static Fields)
  • Class Variables (Static Fields)
  • Declaration: Declared inside methods, constructors, or blocks (like if, for, try-catch).
  • Scope: Visible only within the block (method, constructor, etc.) where they are declared.
  • Lifetime: Created when the block is entered and destroyed when the block is exited.
  • Initialization: Must be explicitly initialized before being used. They do not have default values.
  • Access Modifiers: Cannot use access modifiers (like public, private).
  • Memory: Typically allocated on the stack.
public class LocalVariableDemo {
public void calculateSum() {
int x = 10; // Local variable x, initialized
int y = 20; // Local variable y, initialized
int sum = x + y; // Local variable sum, initialized
System.out.println("Sum is: " + sum);
// int z; // Declared but not initialized
// System.out.println(z); // Compile-time error: variable z might not have been initialized
}
public void processValue(int value) { // 'value' is a local variable (parameter)
if (value > 5) {
String message = "Value is greater than 5"; // message scope is only inside the if block
System.out.println(message);
}
// System.out.println(message); // Compile-time error: cannot find symbol 'message'
}
public static void main(String[] args) {
LocalVariableDemo demo = new LocalVariableDemo();
demo.calculateSum();
demo.processValue(10);
}
}

Since Java 10, you can use the var keyword to declare local variables without explicitly stating the type. The compiler infers the type from the initializer.

  • var can only be used for local variables with an initializer.
  • Cannot be used for instance/class variables, method parameters, or return types.
  • Improves readability for complex types but should be used judiciously.
public void processData() {
var count = 100; // Inferred as int
var name = "Bob"; // Inferred as String
var prices = new java.util.ArrayList<Double>(); // Inferred as ArrayList<Double>
System.out.println("Count: " + count);
System.out.println("Name: " + name);
prices.add(19.99);
System.out.println("Prices: " + prices);
// var n; // Error: cannot use 'var' on variable without initializer
// var lambda = () -> {}; // Error: lambda needs explicit target type
}
  • Declaration: Declared inside a class but outside any method, constructor, or block, without the static keyword.
  • Scope: Visible to all methods, constructors, and blocks within the class. Can be accessed from other classes depending on access modifiers (public, protected, private, default).
  • Lifetime: Created when an object (instance) of the class is created using new. Destroyed when the object is garbage collected.
  • Initialization: Have default values (0 for numbers, false for boolean, null for object references). Can be explicitly initialized during declaration or in constructors.
  • Access Modifiers: Can use access modifiers (public, private, protected, default). private is often recommended for encapsulation.
  • Memory: Allocated on the heap as part of the object’s memory.
  • Association: Each object of the class has its own copy of instance variables.
public class Product {
// Instance variables
private String productName; // Default value null
public double price; // Default value 0.0
private int stockLevel = 0; // Explicitly initialized
// Constructor to initialize instance variables
public Product(String name, double price) {
this.productName = name; // 'this' refers to the current object's variables
this.price = price;
}
public void setStockLevel(int level) {
if (level >= 0) {
this.stockLevel = level;
}
}
public void displayProduct() {
System.out.println("Product: " + this.productName);
System.out.println("Price: " + this.price);
System.out.println("Stock: " + this.stockLevel);
}
public static void main(String[] args) {
Product laptop = new Product("Laptop", 1200.50);
laptop.setStockLevel(50);
Product keyboard = new Product("Keyboard", 75.00);
// keyboard.stockLevel defaults to 0 initially
laptop.displayProduct();
System.out.println("---");
keyboard.displayProduct();
// Accessing public instance variable directly (generally discouraged)
System.out.println("Keyboard price: " + keyboard.price);
}
}
  • Declaration: Declared with the static keyword inside a class, outside any method, constructor, or block.
  • Scope: Similar to instance variables regarding access modifiers, but accessed using the class name (ClassName.variableName).
  • Lifetime: Created when the class is loaded by the JVM and destroyed when the class is unloaded (usually when the application terminates).
  • Initialization: Have default values (like instance variables). Can be initialized during declaration or in a static initializer block.
  • Access Modifiers: Can use access modifiers.
  • Memory: Allocated in a special area of memory (often part of the heap or Metaspace depending on JVM version) associated with the class itself, not individual objects.
  • Association: Only one copy exists per class, shared among all objects of that class.

Common Uses: Constants (public static final) and counters shared across all instances.

public class Counter {
// Instance variable: each object has its own count
private int instanceCount = 0;
// Class variable: shared among all Counter objects
private static int totalCount = 0;
// Constant: public, static, final
public static final String DEFAULT_NAME = "Generic Counter";
// Static initializer block (runs when class is loaded)
static {
System.out.println("Counter class loaded. Initial totalCount: " + totalCount);
// Can do complex static initialization here
}
public Counter() {
instanceCount++; // Increment this object's count
totalCount++; // Increment the shared total count
System.out.println("Counter object created. Instance: " + instanceCount + ", Total: " + totalCount);
}
public int getInstanceCount() {
return this.instanceCount; // Access instance variable
}
public static int getTotalCount() {
// Cannot access 'this' or instance variables from a static context
// System.out.println(instanceCount); // Error!
return totalCount; // Access static variable
}
public static void main(String[] args) {
System.out.println("Default Name: " + Counter.DEFAULT_NAME); // Access constant
System.out.println("Initial Total: " + Counter.getTotalCount()); // Access static method
Counter c1 = new Counter();
Counter c2 = new Counter();
Counter c3 = new Counter();
System.out.println("c1 instance count: " + c1.getInstanceCount()); // Should be 1
System.out.println("c2 instance count: " + c2.getInstanceCount()); // Should be 1
System.out.println("Final Total Count (via static method): " + Counter.getTotalCount()); // Should be 3
System.out.println("Final Total Count (via instance c1): " + c1.totalCount); // Works, but discouraged (access via ClassName)
}
}
  • Use local variables for temporary storage within a method or block.
  • Use instance variables to store the state (attributes) specific to each object.
  • Use class variables (static fields) for constants or data shared across all instances of a class.