杰瑞科技汇

Java内部类为何存在及如何使用?

Of course! Let's break down inner classes in Java, from the basics to more advanced topics.

Java内部类为何存在及如何使用?-图1
(图片来源网络,侵删)

What is an Inner Class?

An inner class is a nested class that is not declared static. It is defined within another class, known as the outer class.

Think of it as a "helper class" that has a special, privileged relationship with its outer class. It can access all members (fields and methods) of the outer class, including its private members.


Why Use Inner Classes?

Inner classes are used primarily for two reasons:

  1. Logical Grouping: To logically group classes that are only used in one place. If a class is only relevant to another single class, making it an inner class makes the package more organized.
  2. Access to Outer Class Members: This is the most powerful feature. An inner class can directly access the instance variables and methods of its outer class, even if they are private. This tight coupling can simplify code that is heavily intertwined.

Types of Inner Classes

Java has four types of inner classes. It's crucial to understand the differences, especially between member inner classes and static nested classes.

Java内部类为何存在及如何使用?-图2
(图片来源网络,侵删)

Member Inner Class (or simply, Inner Class)

This is the most common type. It's a non-static class defined directly inside another class.

Key Characteristics:

  • It is associated with an instance of the outer class.
  • It can access all members (including private ones) of the outer class.
  • It cannot have static declarations (except for static final constants).

Example:

class OuterClass {
    private int outerData = 10;
    // Member inner class
    class InnerClass {
        public void displayData() {
            // Inner class can access private members of the outer class
            System.out.println("Accessing outerData from InnerClass: " + outerData);
        }
    }
    public void createInnerInstance() {
        // To create an instance of the inner class, you need an instance of the outer class
        InnerClass inner = new InnerClass();
        inner.displayData();
    }
}
// How to use it from another class
public class Main {
    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        // Method 1: Through a method of the outer class
        outer.createInnerInstance(); // Output: Accessing outerData from InnerClass: 10
        // Method 2: Directly from outside
        OuterClass.InnerClass inner = outer.new InnerClass();
        inner.displayData(); // Output: Accessing outerData from InnerClass: 10
    }
}

Static Nested Class

This is a nested class declared with the static keyword. It's essentially a top-level class that is nested for packaging convenience.

Java内部类为何存在及如何使用?-图3
(图片来源网络,侵删)

Key Characteristics:

  • It is not associated with an instance of the outer class.
  • It can only access static members of the outer class. It cannot access instance members (outerData in our example).
  • It can have static declarations.
  • You instantiate it directly using the outer class name, without needing an outer instance.

Example:

class OuterClass {
    private static int staticOuterData = 100;
    private int instanceOuterData = 200; // CANNOT be accessed by static nested class
    // Static nested class
    static class StaticNestedClass {
        public void displayData() {
            // Can only access static members of the outer class
            System.out.println("Accessing staticOuterData: " + staticOuterData);
            // The following line would cause a COMPILE ERROR:
            // System.out.println("Accessing instanceOuterData: " + instanceOuterData);
        }
    }
}
// How to use it
public class Main {
    public static void main(String[] args) {
        // No need for an instance of OuterClass!
        OuterClass.StaticNestedClass staticNested = new OuterClass.StaticNestedClass();
        staticNested.displayData(); // Output: Accessing staticOuterData: 100
    }
}

Crucial Difference: OuterClass.InnerClass vs. OuterClass.StaticNestedClass

  • outer.new InnerClass() -> Requires an instance of the outer class.
  • new OuterClass.StaticNestedClass() -> Does not require an instance of the outer class.

Local Inner Class

A class defined inside a method or a scope block (like an if or for loop).

Key Characteristics:

  • Its scope is limited to the method or block where it's defined.
  • It can access final or effectively final local variables of the enclosing method.
  • It cannot use access specifiers (public, private, etc.); its scope is always restricted.

Example:

class OuterClass {
    public void methodWithLocalClass() {
        final int localVar = 50; // Must be final or effectively final
        // Local inner class
        class LocalInnerClass {
            public void printLocalVar() {
                System.out.println("Accessing localVar from LocalInnerClass: " + localVar);
            }
        }
        // Can only be instantiated within this method
        LocalInnerClass localInner = new LocalInnerClass();
        localInner.printLocalVar();
    }
}
// How to use it
public class Main {
    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        outer.methodWithLocalClass(); // Output: Accessing localVar from LocalInnerClass: 50
    }
}

Anonymous Inner Class

This is a special case of a local inner class that has no name. It's a way to create a class and its instance in a single expression. It's commonly used for:

  • Implementing an interface on the fly.
  • Extending a class (often an abstract class) without giving the subclass a name.

Key Characteristics:

  • It's declared and instantiated at the same time.
  • It can only have instance initializers (no constructors).
  • It must extend a class or implement an interface.

Example 1: Implementing an Interface

// An interface
interface Greeting {
    void sayHello();
}
// How to use it
public class Main {
    public static void main(String[] args) {
        // Creating an instance of an anonymous class that implements Greeting
        Greeting greeting = new Greeting() {
            @Override
            public void sayHello() {
                System.out.println("Hello, World! (from an anonymous class)");
            }
        };
        greeting.sayHello(); // Output: Hello, World! (from an anonymous class)
    }
}

Modern Java (Java 8+): This is often replaced by a lambda expression: Greeting greeting = () -> System.out.println("Hello, World! (from a lambda)");

Example 2: Extending a Class

// An abstract class
abstract class Animal {
    public abstract void makeSound();
}
// How to use it
public class Main {
    public static void main(String[] args) {
        // Creating an instance of an anonymous class that extends Animal
        Animal dog = new Animal() {
            @Override
            public void makeSound() {
                System.out.println("Woof!");
            }
        };
        dog.makeSound(); // Output: Woof!
    }
}

Summary Table

Type Declaration Access to Outer Class Members Instantiation Common Use Case
Member Inner Class class Outer { class Inner { } } Yes (all members, including private) Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
Helper classes that need access to outer instance state.
Static Nested Class class Outer { static class Inner { } } Only static members Outer.Inner inner = new Outer.Inner(); When you want to logically group a class with its outer class but don't need access to instance state.
Local Inner Class Inside a method or block Yes, and final local variables of the method Only within the method/block where it's defined. Small, specialized classes used by a single method.
Anonymous Inner Class new Interface() { ... } or new AbstractClass() { ... } Yes, and final local variables of the method new Interface() { ... } One-off implementations of interfaces or extensions of classes, especially in event handling.
分享:
扫描分享到社交APP
上一篇
下一篇