Java
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Java
-
Section 4: Collections Framework
-
Section 5: Exception Handling
-
Section 6: Generics
-
Section 7: Functional Java
-
Section 8: Concurrency
-
Section 9: I/O and NIO
-
Section 10: JVM Internals
-
Section 11: Modern Java Features
-
Section 12: Build Tools and Project Structure
-
Section 13: Testing
-
Section 14: Databases and Persistence
-
Section 15: Networking
-
Section 16: Design and Best Practices
-
Section 17: Reflection and Annotations
-
Section 18: Logging and Diagnostics
-
Section 19: Date, Time, and Internationalization
-
Section 20: Java Platform Module System
-
Section 21: Security in Java
-
Section 22: Advanced Collections and Data Structures
-
Section 23: More Concurrency Patterns
-
Section 24: Compression, Files, and System Integration
-
Section 25: GUI Programming
-
Section 26: Practical Projects
-
Section 27: Data Structures and Algorithms
-
Section 28: Interview and Algorithm Practice
-
Section 29: JSON and Data Interchange
-
Section 30: More Concurrency Utilities
-
Section 31: More Collections and Streams Practice
-
Section 32: More File and System Programming
-
Section 33: Standard Library Deep Dive
-
Section 34: More Practice and Drills
-
Section 35: More Testing and Quality
-
Section 36: More Design Patterns and Architecture
-
Section 37: Career and Ecosystem
-
Section 38: More OOP and Architecture Practice
-
Section 39: More Enterprise Concepts
-
Section 40: Advanced JavaFX
-
Section 41: More Interview Practice
37: Nested and Inner Classes
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
GameWorldwith a private double fieldgravity = 9.81. - Create a non-static inner class
PlayerinsideGameWorld. - Inside
Player, create a methodjump()that prints: "Jumping with gravity [gravity value]". - In your
mainmethod, instantiate aGameWorldobject. - Use that world instance to create a
Playerobject. - 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.
There are no comments for now.