一、什么是内部类
内部类是定义在另一个类内部的类,它可以直接访问外部类的所有成员(包括私有成员),是实现封装、回调和高内聚设计的核心语法。
Java里面不仅可以在文件里定义类,还可以在类里嵌套类,这种就是内部类。
这种设计主要是为了解决一些实际问题,比如:
某个类只为另一个类服务时,不暴露它的存在;
表达逻辑更紧耦的协作关系;
实现更优雅的回调、观察者、迭代器等模式;
代替多继承带来的复杂性。
java
package com.lazy.snail.day15;
/**
* @ClassName Outer
* @Description TODO
* @Author lazysnail
* @Date 2025/5/29 9:21
* @Version 1.0
*/
public class Outer {
private String name = "我是Outer";
public class Inner {
public void showName() {
System.out.println(name);
}
}
}
上述案例中,Outer是定义的一个普通类,Inner是在Outer类中(类定义大括号内)定义的一个内部类。
编译项目(IDEA中使用快捷键Ctrl + F9),然后找到对应字节码文件(.class)。
项目字节码文件输出路径一般在项目中有个默认路径,当然也可以自定义。
使用快捷键Ctrl + Shift + Alt + S打开项目结构-->Compiler output设置的路径就是编译后文件所在路径:

然后根据包名,类名,找到对应的字节码文件。

可以看到两个字节码文件,Outer.class和Outer$Inner.class。
这种命名方式是编译器决定的。
注意下面这种形式并不是内部类:
java
package com.lazy.snail.day15;
/**
* @ClassName Outer
* @Description TODO
* @Author lazysnail
* @Date 2025/5/29 9:21
* @Version 1.0
*/
public class Outer {
private String name = "我是Outer";
}
class Inner {
}
编译后的结果:

这种形式只是在同一个源文件中定义了两个类,不存在嵌套的关系,相互独立。
二、四种内部类
2.1 成员内部类
第一章的案例其实就是成员内部类。
java
package com.lazy.snail.day15;
/**
* @ClassName Outer
* @Description TODO
* @Author lazysnail
* @Date 2025/5/29 9:21
* @Version 1.0
*/
public class Outer {
private String name = "我是Outer";
public class Inner {
public void showName() {
System.out.println(name);
}
}
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.showName();
}
}
Inner和Outer存在绑定关系,Inner可以访问外部类的所有成员,包括私有字段。
内部类编译后的文件名Outer$Inner.class。
成员内部类持有外部类的引用,如果生命周期不一致,可能导致外部类无法被GC。
2.2 静态内部类
静态内部类不依赖外部类实例。
只能访问外部类的静态成员。
在集合框架中常见。

上图是HashMap的源代码,Node类就是HashMap中定义的一个静态内部类。
2.3 局部内部类
局部内部类定义在方法里,作用域仅限方法内部。
可以访问方法里的final或effectively final变量。
用于封装临时的小逻辑块。
java
package com.lazy.snail.day15;
/**
* @ClassName Outer2
* @Description TODO
* @Author lazysnail
* @Date 2025/5/29 10:12
* @Version 1.0
*/
public class Outer2 {
public void great(String name) {
class Greater {
public void sayHi() {
System.out.println("你好 " + name);
}
}
new Greater().sayHi();
}
public static void main(String[] args) {
Outer2 outer2 = new Outer2();
outer2.great("懒惰蜗牛");
}
}
Java 8+,方法参数/局部变量不需要显式加final,只要没被修改,编译器会隐式处理成final(effectively final)
2.4 匿名内部类
匿名内部类就是没有名字的内部类。
主要用于快速实现接口或抽象类。
在事件监听、线程创建等场景中常见。
匿名内部类不能有构造方法,也不能实现多个接口。
如果你写过线程相关的代码,你应该见过这段代码:
java
package com.lazy.snail.day15;
/**
* @ClassName Outer3
* @Description TODO
* @Author lazysnail
* @Date 2025/5/29 10:21
* @Version 1.0
*/
public class Outer3 {
public static void main(String[] args) {
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("跑线程任务");
}
};
new Thread(task).start();
}
}
其实这段代码中task的创建等价于:
java
class AnonymousRunnable implements Runnable {
@Override
public void run() {
System.out.println("跑线程任务");
}
}
Runnable task = new AnonymousRunnable();
上下一对比,可以看出,匿名内部类就是适用于快速创建线程任务且实现简单的场景。
单纯的创建一个简单的线程任务,我们没必要再去写个具体的类来实现Runnable接口,再创建对象。
在编译后的字节码文件中,会出现Outer3$1.class文件,该文件反编译后:

其实就是等价代码的逻辑。
Java 8+引入Lambda表达式后,代码可以进一步简化成:
java
package com.lazy.snail.day15;
/**
* @ClassName Outer3
* @Description TODO
* @Author lazysnail
* @Date 2025/5/29 10:21
* @Version 1.0
*/
public class Outer3 {
public static void main(String[] args) {
Runnable task = () -> System.out.println("跑线程任务");
new Thread(task).start();
}
}
Lambda表达式的写法不会再出现Outer3$1.class这样的字节码。
匿名内部类的简单演进过程:

下面是Lambda表达式和匿名内部类的差异总结:
| 特性 | Lambda表达式 | 匿名内部类 |
|---|---|---|
| 本质 | 函数式接口的简洁实现 | 马上就创建类实例 |
| 语法结构 | (params) -> expression | new Interface() { 方法实现 } |
| 编译机制 | 使用invokedynamic指令动态生成 | 生成独立.class文件(比如Outer3$1.class) |
| 作用域 | 共享外围作用域 | 有独立作用域 |
| this关键字 | 指向外围类实例 | 指向自身实例 |
| 变量捕获 | 可以捕获effectively final变量(隐式final) | 需显式final变量 |
| 内存占用 | 较小(JVM级优化) | 较大(生成新类) |
| 方法支持 | 只能实现单个抽象方法 | 可实现多方法 |
| 构造函数 | 不支持 | 支持实例初始化块 |
| 接口类型 | 仅限函数式接口(单一抽象方法) | 支持任意接口/抽象类 |
| 调试信息 | 栈轨迹更简洁 | 有完整类名(但匿名类名可读性差) |
| 字节码验证 | 运行时校验 | 编译时校验 |
结语
内部类这种设计让类的定义不局限于文件或包,可以灵活嵌套,配合作用域、访问控制、编译策略,一起构建高内聚、低耦合的结构。
在真实项目开发里,要不要使用内部类,关键在于能不能提升代码的可读性与模块性。
不是所有内部类都值得保留,也不是所有逻辑都该外提成独立类。
如果你把内部类当成语法糖,那它就是个工具;
但如果你把它当作结构表达力的一部分,那它就是一种架构语言。
下一篇预告
Day16 | Java异常机制详解
如果你觉得这系列文章对你有帮助,欢迎关注专栏,我们一起坚持下去!
更多文章请关注我的公众号《懒惰蜗牛工坊》