📚 目录
🔍 什么是内部类
内部类(Inner Class) 是定义在另一个类内部的类,主要作用包括:
-
实现代码逻辑的更好封装
-
直接访问外部类的私有成员
-
构建更简洁的回调机制
-
支持多继承的变通实现
🧩 成员内部类
基本语法
class Outer { private int value = 10; class Inner { void print() { System.out.println("Value: " + value); // 直接访问外部类私有成员 } } }
核心特性
-
自动持有外部类实例的引用 (
Outer.this
) -
不能定义静态成员(Java 16+ 已允许)
-
实例化方式:
Outer outer = new Outer(); Outer.Inner inner = outer.new Inner();
🏗️ 静态内部类
典型实现
class Outer { static class StaticInner { void staticMethod() { System.out.println("Static inner method"); } } }
特色对比
特性 | 成员内部类 | 静态内部类 |
---|---|---|
外部类引用 | 必须持有隐含引用 | 无隐含引用 |
访问外部类成员 | 可直接访问所有成员 | 只能访问静态成员 |
实例化方式 | outer.new Inner() | new Outer.StaticInner() |
🔧 局部内部类
方法内部的类
class Outer { void method() { final int localVar = 20; class LocalInner { void display() { System.out.println(localVar); // 必须final或等效final } } new LocalInner().display(); } }
重要特点
-
作用域仅限于定义的方法/代码块
-
自动转化为常规的带编号类文件 (例如:
Outer$1LocalInner.class
) -
无法添加访问修饰符
🎭 匿名内部类
经典案例
button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("Button clicked!"); } });
编译原理
// 实际生成示例 class Outer$1 implements ActionListener { Outer$1(Outer this$0) { this.this$0 = this$0; } @Override public void actionPerformed(ActionEvent e) { System.out.println("Button clicked!"); } }
⚙️ 原理分析
反编译示例
// 成员内部类被编译为独立类 class Outer$Inner { final Outer this$0; Outer$Inner(Outer outer) { this.this$0 = outer; } }
🗂️ 使用场景对比
类型 | 典型应用场景 | 优点 | 缺点 |
---|---|---|---|
成员内部类 | 迭代器实现、Adapter模式 | 完全访问外部类成员 | 内存泄漏风险 |
静态内部类 | 工具类、单例模式 | 不依赖外部实例 | 无法访问非静态域 |
局部内部类 | 复杂算法封装 | 限制作用域 | 只能访问final变量 |
匿名内部类 | GUI事件处理、简单回调 | 立即实现 | 代码可读性降低 |
❓ 常见问题
Q1:为什么局部内部类只能访问final变量?
当局部内部类访问的局部变量被JVM处理为"捕获变量"时,需要保证其生命周期与内部类实例一致,final保证值不变。
Q2:如何避免内部类内存泄漏?
对非静态内部类持有外部类实例的情况,在使用完毕后显式中断引用:
class Outer { void createInner() { Inner inner = new Inner(); // 使用后解除关联 inner.dispose(); } class Inner { void dispose() { outerRef = null; // 手动释放 } } }
🏆 最佳实践
-
优先选择静态内部类:除非需要访问外部类实例成员
-
控制内部类可见性:尽可能使用private修饰内部类
-
Lambda表达式替代:Java 8+优先用Lambda代替部分匿名内部类
-
防御性拷贝:返回内部类引用前进行拷贝防御
-
资源释放:对长期存活的内部类实现Closeable接口