Skip to Content
Course content

37: Nested and Inner Classes

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've seen this specific error trip up almost every junior dev I've mentored. You're trying to organize your code by putting a helper class inside another class—which is a great instinct—but then the compiler starts screaming at you with a message about "non-static variables" or "static context."

public class BankAccount {
    private double balance = 100.0;

    public class Transaction {
        public void printDetails() {
            System.out.println("Transaction for balance: " + balance);
        }
    }

    public static void main(String[] args) {
        // This is where it breaks
        BankAccount.Transaction tx = new BankAccount.Transaction(); 
        tx.printDetails();
    }
}

The "Non-Static Variable Cannot Be Referenced" Headache

If you try to compile the code above, Java will throw a fit. The error usually looks something like: non-static variable this cannot be referenced from a static context.

Here is why: Transaction is an inner class. In Java, a non-static inner class is inextricably linked to a specific instance of the outer class. Because Transaction can access the balance field of BankAccount, it needs to know which specific account it belongs to. But the main method is static. It exists independently of any BankAccount object. You're essentially asking Java to create a "transaction" without telling it which "account" that transaction is attached to. It's a logical impossibility in the eyes of the JVM.

Tying the Inner Class to an Instance

To fix this, you have to create the outer object first. You can't just call new BankAccount.Transaction() in a vacuum. You have to tell Java: "Create a Transaction that belongs to this specific BankAccount."

public static void main(String[] args) {
    BankAccount myAccount = new BankAccount();
    
    // Notice the syntax change: we use the instance 'myAccount'
    BankAccount.Transaction tx = myAccount.new Transaction(); 
    tx.printDetails();
}

That myAccount.new Transaction() syntax is a bit clunky, I'll admit, but it explicitly binds the inner class instance to the outer class instance. Now, when printDetails() is called, it knows exactly whose balance to look at.

When to Use Static Nested Classes Instead

Now, you might be thinking, "Why not just make everything static?" Well, you should if the nested class doesn't actually need to touch the outer class's private fields. If Transaction was just a data holder that didn't care about the balance, you'd make it a static nested class.

public class BankAccount {
    public static class TransactionLog {
        public void log(String msg) {
            System.out.println("LOG: " + msg);
        }
    }
}

By adding static, TransactionLog no longer requires an instance of BankAccount to exist. You can instantiate it normally: new BankAccount.TransactionLog(). I generally prefer static nested classes unless there's a very strong reason to have a tight, stateful coupling between the two. It keeps the memory footprint cleaner and the logic more decoupled.

Local Classes and the Quick-and-Dirty Anonymous Class

Finally, there's the local class—a class defined inside a method. You won't use these often, but you'll see them in legacy code. More common are anonymous inner classes. These are classes without a name, defined and instantiated in a single breath. You'll see these everywhere when dealing with event listeners or old-school threading.

Think of them as "disposable" classes. You use them when you need to implement an interface once, right here, right now, and you never plan on reusing that specific implementation elsewhere in your app. It's a shortcut that saves you from creating a whole new .java file for a three-line implementation.




📋 Practical Task

Build a Custom Game Component System

You are building a simple game engine. You need to create a GameWorld class that manages a Player. However, the Player should be an inner class because a player cannot exist without a world to live in, and the player needs direct access to the world's gravity setting.

  • Create a class GameWorld with a private double field gravity = 9.81.
  • Create a non-static inner class Player inside GameWorld.
  • Inside Player, create a method jump() that prints: "Jumping with gravity [gravity value]".
  • In your main method, instantiate a GameWorld object.
  • Use that world instance to create a Player object.
  • Call the jump() method on the player.

Challenge: Also add a static nested class called GameSettings inside GameWorld that holds a static constant VERSION = "1.0.0". Print this version in main without needing to instantiate the GameWorld.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.