Java Inner Classes: A Complete Guide with Examples and Exercises
Inner classes in Java provide a way to logically group classes that are only used in one place, which helps to keep code more readable and organized. Inner classes are nested within another class and can be a powerful way to associate certain helper or utility classes with their outer class.
Table of Contents
- Introduction to Inner Classes
- Types of Inner Classes
- Why Use Inner Classes?
- Member Inner Classes
- Static Nested Classes
- Local Inner Classes
- Anonymous Inner Classes
- Exercises
1. Introduction to Inner Classes
An inner class is a class declared within another class in Java. Inner classes have access to the members (both static and instance) of the outer class and are commonly used when a class is only relevant in the context of another class.
Java provides four main types of inner classes:
- Member Inner Classes
- Static Nested Classes
- Local Inner Classes
- Anonymous Inner Classes
Each type serves specific use cases and has distinct characteristics.
2. Types of Inner Classes
Java’s inner classes are classified based on their scope and behavior:
- Member Inner Classes: Defined as a member of the outer class.
- Static Nested Classes: Similar to a member inner class, but static.
- Local Inner Classes: Defined within a method or a block.
- Anonymous Inner Classes: Created on the fly, typically for a one-time use.
3. Why Use Inner Classes?
Inner classes help in logically grouping classes that are only used within one place, improving encapsulation and readability. Some benefits include:
- Enhanced Readability: Grouping relevant classes together.
- Encapsulation: Protecting implementation details.
- Access to Outer Class Members: Inner classes have access to private members of the outer class, reducing the need for accessor methods.
4. Member Inner Classes
A member inner class is a non-static class that is declared within the outer class. It can access both static and non-static members of the outer class.
Example of Member Inner Class
class OuterClass {
private String message = "Hello from OuterClass";
class InnerClass {
public void printMessage() {
System.out.println(message);
}
}
}
public class Main {
public static void main(String[] args) {
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.new InnerClass();
inner.printMessage(); // Outputs: Hello from OuterClass
}
}
Explanation
In this example, InnerClass
is a member inner class within OuterClass
. It has access to the message
field of OuterClass
, even though it is private.
5. Static Nested Classes
A static nested class is similar to a member inner class, but it is static. Unlike member inner classes, static nested classes can only access the static members of the outer class.
Example of Static Nested Class
class OuterClass {
static String staticMessage = "Hello from Static OuterClass";
static class StaticNestedClass {
public void printStaticMessage() {
System.out.println(staticMessage);
}
}
}
public class Main {
public static void main(String[] args) {
OuterClass.StaticNestedClass nested = new OuterClass.StaticNestedClass();
nested.printStaticMessage(); // Outputs: Hello from Static OuterClass
}
}
Explanation
The StaticNestedClass
does not require an instance of OuterClass
to be instantiated, as it can directly access the staticMessage
variable because it’s static.
6. Local Inner Classes
Local inner classes are defined within a method or a block. They are only accessible within that method or block, and they cannot have access modifiers.
Example of Local Inner Class
class OuterClass {
public void display() {
class LocalInnerClass {
public void printMessage() {
System.out.println("Hello from LocalInnerClass");
}
}
LocalInnerClass local = new LocalInnerClass();
local.printMessage();
}
}
public class Main {
public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.display(); // Outputs: Hello from LocalInnerClass
}
}
Explanation
LocalInnerClass
is declared within the display
method of OuterClass
, so it is only accessible inside that method.
7. Anonymous Inner Classes
An anonymous inner class is a local inner class without a name and is used for creating a single object with a specific implementation, often when implementing interfaces or abstract classes.
Example of Anonymous Inner Class
abstract class Animal {
public abstract void sound();
}
public class Main {
public static void main(String[] args) {
Animal dog = new Animal() {
public void sound() {
System.out.println("Dog barks");
}
};
dog.sound(); // Outputs: Dog barks
}
}
Explanation
In this example, an anonymous inner class is created to implement the abstract sound
method of the Animal
class. This is often used to provide custom implementations without explicitly defining a new class.
8. Exercises
Exercise 1: Member Inner Class
Create a class Library
with a member inner class Book
. The Library
class should have a field libraryName
, and the Book
class should have a method printLibraryName
that accesses libraryName
.
Write a main
method to test the functionality by creating an instance of Book
and calling printLibraryName
.
Exercise 2: Static Nested Class
Create a class University
with a static nested class Department
. The University
class should have a static field universityName
. The Department
class should have a method printUniversityName
that accesses universityName
.
Write a main
method to create an instance of Department
and call printUniversityName
.
Exercise 3: Local Inner Class
In a class Computer
, create a method turnOn
that contains a local inner class Processor
. The Processor
class should have a method printStatus
that prints “Processor is running”.
In turnOn
, create an instance of Processor
and call printStatus
.
Exercise 4: Anonymous Inner Class
Create an interface Shape
with a method draw()
. In your main
method, create an anonymous inner class to implement Shape
for a Circle
and override draw()
to print “Drawing a Circle”.
Sample Solution for Exercise 1: Member Inner Class
class Library {
private String libraryName = "City Library";
class Book {
public void printLibraryName() {
System.out.println("Library: " + libraryName);
}
}
}
public class Main {
public static void main(String[] args) {
Library library = new Library();
Library.Book book = library.new Book();
book.printLibraryName(); // Outputs: Library: City Library
}
}
Sample Solution for Exercise 2: Static Nested Class
class University {
static String universityName = "National University";
static class Department {
public void printUniversityName() {
System.out.println("University: " + universityName);
}
}
}
public class Main {
public static void main(String[] args) {
University.Department department = new University.Department();
department.printUniversityName(); // Outputs: University: National University
}
}
Conclusion
Java inner classes add flexibility and organization to your code, especially when smaller helper classes are only relevant within the context of a single outer class. By using different types of inner classes, such as member inner classes, static nested classes, local inner classes, and anonymous inner classes, you can manage scope, access, and modularity more effectively. With the examples and exercises provided, you can gain practical experience in applying inner classes to your projects. Happy coding!