1. 简介
本文将快速介绍 Java 语言中的嵌套类概念。
简单来说,Java 允许我们在一个类内部定义另一个类。嵌套类能帮助我们实现以下目标:
- ✅ 逻辑上组织仅在某处使用的类
- ✅ 提升代码可读性和可维护性
- ✅ 增强封装性
在深入之前,先了解 Java 中嵌套类的四种类型:
- 静态嵌套类
- 非静态嵌套类(内部类)
- 局部类
- 匿名类
接下来我们将逐一详细解析。
2. 静态嵌套类
关于静态嵌套类,记住这几个关键点:
- ✅ 属于外部类本身,而非外部类实例
- ✅ 声明时可使用任意访问修饰符
- ✅ 只能访问外部类的静态成员
- ✅ 可定义静态和非静态成员
声明方式示例:
public class Enclosing {
private static int x = 1;
public static class StaticNested {
private void run() {
// 方法实现
}
}
@Test
public void test() {
Enclosing.StaticNested nested = new Enclosing.StaticNested();
nested.run();
}
}
3. 非静态嵌套类
关于非静态嵌套类(内部类),记住这些要点:
- ✅ 也称为内部类
- ✅ 声明时可使用任意访问修饰符
- ✅ 与外部类实例绑定(类似实例变量/方法)
- ✅ 可访问外部类的所有成员(静态/非静态)
- ✅ 只能定义非静态成员
声明方式示例:
public class Outer {
public class Inner {
// ...
}
}
⚠️ 关键区别:声明时是否带 static
关键字。虽然语法上仅一字之差,但语义差异巨大——内部类实例与外部类实例绑定,因此能访问其成员。选择嵌套类型时需特别注意这点。
创建内部类实例必须先创建外部类实例:
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
3.1. 局部类
局部类是内部类的一种特殊形式——在方法或作用域块内定义的类。
记住这些特点:
- ✅ 声明时不能有访问修饰符
- ✅ 可访问外部上下文的静态/非静态成员
- ✅ 只能定义实例成员
示例代码:
public class NewEnclosing {
void run() {
class Local {
void run() {
// 方法实现
}
}
Local local = new Local();
local.run();
}
@Test
public void test() {
NewEnclosing newEnclosing = new NewEnclosing();
newEnclosing.run();
}
}
3.2. 匿名类
匿名类用于快速实现接口或抽象类,无需创建可重用实现类。
记住这些要点:
- ✅ 声明时不能有访问修饰符
- ✅ 可访问外部上下文的静态/非静态成员
- ✅ 只能定义实例成员
- ❌ 唯一不能定义构造器的嵌套类
- ❌ 不能继承/实现其他类或接口
先定义一个抽象类:
abstract class SimpleAbstractClass {
abstract void run();
}
匿名类实现示例:
public class AnonymousInnerUnitTest {
@Test
public void whenRunAnonymousClass_thenCorrect() {
SimpleAbstractClass simpleAbstractClass = new SimpleAbstractClass() {
void run() {
// 方法实现
}
};
simpleAbstractClass.run();
}
}
想深入了解?可参考我们的 Java 匿名类教程。
4. 成员遮蔽
当内部类成员与外部类成员同名时,内部类成员会遮蔽外部类成员。
此时:
this
关键字指向嵌套类实例- 通过
外部类名.this
访问外部类成员
示例代码:
public class NewOuter {
int a = 1;
static int b = 2;
public class InnerClass {
int a = 3;
static final int b = 4;
public void run() {
System.out.println("a = " + a); // 输出内部类 a
System.out.println("b = " + b); // 输出内部类 b
System.out.println("NewOuterTest.this.a = " + NewOuter.this.a); // 访问外部类 a
System.out.println("NewOuterTest.b = " + NewOuter.b); // 访问外部类静态 b
System.out.println("NewOuterTest.this.b = " + NewOuter.this.b); // 访问外部类 b
}
}
@Test
public void test() {
NewOuter outer = new NewOuter();
NewOuter.InnerClass inner = outer.new InnerClass();
inner.run();
}
}
5. 序列化踩坑
尝试序列化嵌套类时,为避免 java.io.NotSerializableException
,必须:
- ✅ 将嵌套类声明为
static
- ✅ 让嵌套类和外部类都实现
Serializable
接口
6. 总结
本文系统介绍了 Java 嵌套类的概念及四种类型,并分析了不同类型中字段可见性和访问修饰符的差异。掌握这些知识能帮你写出更优雅的 Java 代码。
完整示例代码见 GitHub 项目。