Week 1

Environment setup

How Java works

Types and Variables

Arrays

Basic IO

Control Flow

Packages

OOP in Java

Static Members

Practice

Assignment

Back end Track

🎯 Learning Objectives

By the end of this module, you will be able to:


1. The Problem static Solves

Everything 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:

For these, Java provides the static keyword.


2. Static Fields — Shared Across All Instances

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's static formalises this pattern into the language.


3. Static Methods — Called on the Class

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:


4. static final — Constants

Combine 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. All static final constants on their respective classes.


5. Why main is Static

Every 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

6. Static vs Instance — Decision Criteria

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

7. Utility Classes

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.


8. The Common Mistake — Accessing Instance Members from a Static Context

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.

How to fix it

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
}