Skip to content

🔐 内部类与匿名类

内部类概述

内部类(Inner Class)是定义在另一个类内部的类。Java 提供了多种类型的内部类:

  1. 成员内部类(Member Inner Class)
  2. 静态内部类(Static Nested Class)
  3. 局部内部类(Local Inner Class)
  4. 匿名内部类(Anonymous Inner Class)

成员内部类

基本语法

java
public class Outer {
    private String outerField = "外部类字段";
    
    // 成员内部类
    public class Inner {
        private String innerField = "内部类字段";
        
        public void display() {
            System.out.println("外部类字段: " + outerField);  // 可以访问外部类成员
            System.out.println("内部类字段: " + innerField);
        }
    }
    
    // 创建内部类对象
    public void createInner() {
        Inner inner = new Inner();
        inner.display();
    }
}

使用成员内部类

java
// 创建内部类对象
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();  // 通过外部类对象创建
inner.display();

// 或者
Outer.Inner inner2 = new Outer().new Inner();

访问外部类成员

java
public class Outer {
    private int outerVar = 10;
    
    public class Inner {
        private int innerVar = 20;
        
        public void method() {
            // 访问外部类成员
            System.out.println("外部类变量: " + outerVar);
            System.out.println("外部类变量: " + Outer.this.outerVar);  // 明确指定
            
            // 访问内部类成员
            System.out.println("内部类变量: " + innerVar);
            System.out.println("内部类变量: " + this.innerVar);
        }
    }
}

静态内部类

基本语法

java
public class Outer {
    private static String staticField = "静态字段";
    private String instanceField = "实例字段";
    
    // 静态内部类
    public static class StaticInner {
        public void display() {
            System.out.println("静态字段: " + staticField);  // 只能访问静态成员
            // System.out.println(instanceField);  // ❌ 错误:不能访问实例成员
        }
        
        public static void staticMethod() {
            System.out.println("静态内部类的静态方法");
        }
    }
}

使用静态内部类

java
// 不需要外部类对象,直接创建
Outer.StaticInner staticInner = new Outer.StaticInner();
staticInner.display();

// 调用静态方法
Outer.StaticInner.staticMethod();

局部内部类

基本语法

java
public class Outer {
    private String outerField = "外部类字段";
    
    public void method() {
        final String localVar = "局部变量";  // 必须是 final 或 effectively final
        
        // 局部内部类
        class LocalInner {
            public void display() {
                System.out.println("外部类字段: " + outerField);
                System.out.println("局部变量: " + localVar);
            }
        }
        
        // 在方法内使用
        LocalInner localInner = new LocalInner();
        localInner.display();
    }
}

局部内部类的限制

java
public class Outer {
    public void method() {
        // 局部内部类不能有访问修饰符
        class LocalInner {
            // ❌ public class LocalInner { }  // 错误
            
            // 局部内部类不能有静态成员(Java 16+ 允许)
            // static int staticVar = 10;  // Java 16 之前错误
        }
    }
}

匿名内部类

基本语法

java
// 实现接口
interface Greeting {
    void greet(String name);
}

public class Outer {
    public void method() {
        // 匿名内部类
        Greeting greeting = new Greeting() {
            @Override
            public void greet(String name) {
                System.out.println("Hello, " + name);
            }
        };
        
        greeting.greet("张三");
    }
}

继承类的匿名内部类

java
public class Animal {
    public void makeSound() {
        System.out.println("动物发出声音");
    }
}

public class Outer {
    public void method() {
        // 匿名内部类继承 Animal
        Animal animal = new Animal() {
            @Override
            public void makeSound() {
                System.out.println("匿名动物发出声音");
            }
        };
        
        animal.makeSound();
    }
}

Lambda 表达式(Java 8+)

java
// 函数式接口
interface Calculator {
    int calculate(int a, int b);
}

public class Outer {
    public void method() {
        // 使用匿名内部类
        Calculator calc1 = new Calculator() {
            @Override
            public int calculate(int a, int b) {
                return a + b;
            }
        };
        
        // 使用 Lambda 表达式(更简洁)
        Calculator calc2 = (a, b) -> a + b;
        
        System.out.println(calc1.calculate(5, 3));  // 8
        System.out.println(calc2.calculate(5, 3));  // 8
    }
}

内部类的应用场景

1. 事件处理

java
public class Button {
    private String text;
    private OnClickListener listener;
    
    public interface OnClickListener {
        void onClick();
    }
    
    public void setOnClickListener(OnClickListener listener) {
        this.listener = listener;
    }
    
    public void click() {
        if (listener != null) {
            listener.onClick();
        }
    }
}

// 使用
Button button = new Button();
button.setOnClickListener(new Button.OnClickListener() {
    @Override
    public void onClick() {
        System.out.println("按钮被点击");
    }
});

2. 迭代器实现

java
public class MyList {
    private String[] items = {"a", "b", "c"};
    
    public Iterator<String> iterator() {
        return new Iterator<String>() {
            private int index = 0;
            
            @Override
            public boolean hasNext() {
                return index < items.length;
            }
            
            @Override
            public String next() {
                return items[index++];
            }
        };
    }
}

3. 辅助类封装

java
public class Outer {
    private String data;
    
    // 使用静态内部类封装相关的辅助类
    public static class Builder {
        private String data;
        
        public Builder setData(String data) {
            this.data = data;
            return this;
        }
        
        public Outer build() {
            Outer outer = new Outer();
            outer.data = this.data;
            return outer;
        }
    }
}

// 使用
Outer outer = new Outer.Builder()
    .setData("数据")
    .build();

内部类的优势

1. 访问控制

java
public class Outer {
    private String privateField = "私有字段";
    
    // 内部类可以访问外部类的私有成员
    public class Inner {
        public void accessPrivate() {
            System.out.println(privateField);  // ✅ 可以访问
        }
    }
}

2. 代码组织

java
// 将相关的类组织在一起
public class LinkedList {
    // 节点类作为内部类更合理
    private static class Node {
        Object data;
        Node next;
        
        Node(Object data) {
            this.data = data;
        }
    }
    
    private Node head;
}

3. 实现回调

java
public class EventHandler {
    public void handleEvent(Event event) {
        // 使用匿名内部类实现回调
        event.setOnComplete(new Callback() {
            @Override
            public void onComplete() {
                System.out.println("事件完成");
            }
        });
    }
}

完整示例

java
// 外部类
public class Outer {
    private String outerField = "外部类字段";
    private static String staticField = "静态字段";
    
    // 成员内部类
    public class MemberInner {
        public void display() {
            System.out.println("成员内部类访问: " + outerField);
        }
    }
    
    // 静态内部类
    public static class StaticInner {
        public void display() {
            System.out.println("静态内部类访问: " + staticField);
        }
    }
    
    // 方法中使用局部内部类
    public void methodWithLocalInner() {
        final String localVar = "局部变量";
        
        class LocalInner {
            public void display() {
                System.out.println("局部内部类访问: " + outerField);
                System.out.println("局部变量: " + localVar);
            }
        }
        
        LocalInner localInner = new LocalInner();
        localInner.display();
    }
    
    // 方法中使用匿名内部类
    public void methodWithAnonymous() {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类执行");
            }
        };
        
        new Thread(runnable).start();
    }
}

// 使用示例
public class InnerClassExample {
    public static void main(String[] args) {
        Outer outer = new Outer();
        
        // 成员内部类
        Outer.MemberInner memberInner = outer.new MemberInner();
        memberInner.display();
        
        // 静态内部类
        Outer.StaticInner staticInner = new Outer.StaticInner();
        staticInner.display();
        
        // 局部内部类
        outer.methodWithLocalInner();
        
        // 匿名内部类
        outer.methodWithAnonymous();
    }
}

注意事项

1. 成员内部类不能有静态成员(Java 16+ 允许)

java
public class Outer {
    public class Inner {
        // ❌ Java 16 之前错误
        // static int staticVar = 10;
        
        // ✅ Java 16+ 允许
        static int staticVar = 10;
    }
}

2. 局部变量必须是 final 或 effectively final

java
public void method() {
    final String finalVar = "final";  // ✅ 可以
    String effectivelyFinal = "effectively final";  // ✅ 可以(只赋值一次)
    // String notFinal = "not final";  // ❌ 错误(如果多次赋值)
    
    class LocalInner {
        public void display() {
            System.out.println(finalVar);  // ✅ 可以
            System.out.println(effectivelyFinal);  // ✅ 可以
        }
    }
}

3. 内部类与外部类的 this

java
public class Outer {
    private String name = "Outer";
    
    public class Inner {
        private String name = "Inner";
        
        public void display() {
            System.out.println(this.name);           // Inner
            System.out.println(Outer.this.name);      // Outer
        }
    }
}

最佳实践

1. 优先使用静态内部类

java
// ✅ 如果不访问外部类实例成员,使用静态内部类
public class Outer {
    public static class StaticInner {
        // 不依赖外部类实例
    }
}

// ❌ 如果不必要,避免使用成员内部类(需要外部类实例)

2. 使用 Lambda 替代匿名内部类

java
// ✅ Java 8+ 使用 Lambda
Runnable r = () -> System.out.println("Hello");

// ❌ 不使用匿名内部类(如果可以用 Lambda)
Runnable r = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello");
    }
};

3. 合理使用内部类

java
// ✅ 内部类用于封装相关功能
public class LinkedList {
    private static class Node {
        // 节点类只与链表相关
    }
}

// ❌ 避免过度嵌套

下一步

掌握了内部类与匿名类后,可以继续学习:


💡 提示:内部类和匿名类提供了代码组织和功能封装的有力工具,但要合理使用,避免过度复杂