By the end of this module, you will be able to:
static fields that are shared across all instancesstatic methods on the class itselfstatic final to define constantsmain method must be staticstatic vs instancestatic SolvesEverything you've written in Module 8 belongs to individual objects — each Person has its own name, its own age, its own introduce() method execution. That's instance behaviour, and it's correct for data that varies per object.
But some things don't belong to any specific object. They belong to the class as a whole:
Person objects have been created in total?Person?For these, Java provides the static keyword.
A static field has one copy in memory, shared by every instance of the class. Changing it from one object changes it for all.
public class Person {
// Instance field — each Person has their own
private String name;
// Static field — one copy, shared by ALL Person objects
private static int instanceCount = 0;
public Person(String name) {
this.name = name;
instanceCount++; // every new Person increments the same counter
}
public static int getInstanceCount() {
return instanceCount;
}
}
System.out.println(Person.getInstanceCount()); // 0
Person p1 = new Person("Alice");
Person p2 = new Person("Bob");
Person p3 = new Person("Charlie");
System.out.println(Person.getInstanceCount()); // 3
Notice: getInstanceCount() is called on the class (Person.getInstanceCount()), not on an object — because it's static.
🔍 Coming from JavaScript, there's no direct equivalent — you'd typically store this kind of shared state as a property on the class itself (
Person.count = 0). Java'sstaticformalises this pattern into the language.
A static method belongs to the class, not to any object. You call it on the class name directly without creating an instance first.
public class MathHelper {
public static int square(int n) {
return n * n;
}
public static boolean isEven(int n) {
return n % 2 == 0;
}
}
// No object needed — call directly on the class
int result = MathHelper.square(5); // 25
boolean even = MathHelper.isEven(4); // true
You've been using static methods all along:
Math.abs(-5) — abs is a static method on the Math classArrays.sort(arr) — sort is a static method on the Arrays classInteger.parseInt("42") — parseInt is a static method on the Integer classstatic final — ConstantsCombine static (one shared value) with final (cannot be reassigned) to define constants — values that are fixed for the entire lifetime of the program.
public class Config {
public static final int MAX_AGE = 120;
public static final double TAX_RATE = 0.21;
public static final String DEFAULT_COUNTRY = "Netherlands";
}
System.out.println(Config.MAX_AGE); // 120
System.out.println(Config.TAX_RATE); // 0.21
System.out.println(Config.DEFAULT_COUNTRY); // Netherlands
Config.MAX_AGE = 200; // ❌ Compile error — final cannot be reassigned
Naming convention: static final constants use UPPER_SNAKE_CASE — every word capitalised, separated by underscores.
💡 Built-in examples you've seen:
Integer.MAX_VALUE,Integer.MIN_VALUE,Math.PI. Allstatic finalconstants on their respective classes.
main is StaticEvery Java program starts at main:
public static void main(String[] args) { ... }
The static here is not optional or stylistic — it's required. When the JVM starts your program, no objects exist yet. There's nothing to call an instance method on. The JVM needs to invoke main on the class itself, before any object is created. That's only possible if main is static.
JVM starts
↓
Loads the class (no objects yet)
↓
Calls Main.main() — possible because it's static
↓
Your code runs, objects are created
Use this as a guide when deciding whether a field or method should be static or instance:
| Question | Answer → |
|---|---|
| Does this data vary per object? | Instance field |
| Is this data shared across all objects? | Static field |
| Does this method use or depend on instance fields? | Instance method |
| Does this method work purely on its inputs, no object state needed? | Static method |
| Is this a fixed value that never changes? | static final constant |
Applied to a BankAccount class:
public class BankAccount {
// Instance — each account has its own balance and owner
private String owner;
private double balance;
// Static — one interest rate applies to all accounts
private static double interestRate = 0.035;
// Static final — bank name never changes
public static final String BANK_NAME = "HYF Bank";
// Instance method — uses this.balance (instance state)
public void deposit(double amount) {
this.balance += amount;
}
// Static method — works on inputs only, no instance state needed
public static double calculateInterest(double principal, int years) {
return principal * interestRate * years;
}
}
// Instance method — needs an object
BankAccount account = new BankAccount("Alice", 1000);
account.deposit(500);
// Static method — called on the class
double interest = BankAccount.calculateInterest(1000, 5);
// Static final constant — called on the class
System.out.println(BankAccount.BANK_NAME); // HYF Bank
A utility class is a class that exists purely to group related static methods together. It is never instantiated — you just call its methods directly on the class.
Java's standard library is full of them: Math, Arrays, Collections, Objects.
Here's the pattern for writing your own:
public class StringUtils {
// Private constructor — prevents anyone from creating an instance
private StringUtils() {}
public static String capitalise(String word) {
if (word == null || word.isBlank()) return word;
return word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase();
}
public static boolean isPalindrome(String text) {
String cleaned = text.toLowerCase().replaceAll("\\\\\\\\s+", "");
String reversed = new StringBuilder(cleaned).reverse().toString();
return cleaned.equals(reversed);
}
public static int countWords(String sentence) {
if (sentence == null || sentence.isBlank()) return 0;
return sentence.trim().split("\\\\\\\\s+").length;
}
}
System.out.println(StringUtils.capitalise("hello")); // Hello
System.out.println(StringUtils.isPalindrome("racecar")); // true
System.out.println(StringUtils.countWords("Hello World")); // 2
💡 The private constructor is a deliberate signal: "this class is not meant to be instantiated." If someone tries
new StringUtils(), they get a compile error — your intent is enforced by the code itself.
This is one of the most frequent errors beginners hit, and the error message can feel cryptic at first.
public class Counter {
private int count = 0; // instance field
public static void reset() {
count = 0; // ❌ Cannot access instance field from a static method
}
}
Error: Non-static field 'count' cannot be referenced from a static context
Why? A static method belongs to the class, not any object. When reset() runs, there may be zero objects, one, or a hundred — Java has no way to know which object's count you mean.
Option A — Make the method an instance method (if it should operate on a specific object):
public void reset() { // instance method
this.count = 0; // ✅ clearly refers to this specific object's count
}
Option B — Make the field static (if the value truly should be shared):
private static int count = 0; // static field
public static void reset() {
count = 0; // ✅ one shared count — static method can access it
}
The fix depends on your intent. Ask: should this operate on one specific object or on the class as a whole?
// Also wrong — calling instance method from static context
public class Greeter {
private String message = "Hello";
public static void main(String[] args) {
System.out.println(message); // ❌ static context
greet(); // ❌ static context — greet() is instance
}
public void greet() {
System.out.println(message);
}
}
// Correct — create an object first
public static void main(String[] args) {
Greeter g = new Greeter();
g.greet(); // ✅ calling instance method on an object
}