文章目录
- 一、实例内部类
-
- [1.1 定义](#1.1 定义)
- [1.2 核心特性](#1.2 核心特性)
- [1.3 如何创建实例内部类对象?](#1.3 如何创建实例内部类对象?)
- [1.4 内部类如何访问外部类?](#1.4 内部类如何访问外部类?)
- [1.5 同名冲突怎么解决?](#1.5 同名冲突怎么解决?)
- 二、静态内部类
-
- [2.1 定义](#2.1 定义)
- [2.2 核心特点](#2.2 核心特点)
- [2.3 代码示例](#2.3 代码示例)
- [2.4 什么时候使用静态内部类?](#2.4 什么时候使用静态内部类?)
- 三、局部内部类
-
- [3.1 定义](#3.1 定义)
- [3.2 特点](#3.2 特点)
- [3.3 三种类比较](#3.3 三种类比较)
- [3.4 补充](#3.4 补充)
一、实例内部类
1.1 定义
直接定义在 类的内部、方法外部 ,并且 没有static修饰 的类,就是实例内部类。
java
public class Outer {
//实例内部类
class Inner {
}
}
特点一句话:
内部类对象,必须依附一个外部类对象存在。
没有Outer对象,就不可能有Inner对象。
1.2 核心特性
1.内部类持有外部类的引用
实例内部类对象里,会隐式持有一个外部类对象的引用,类似:
java
Outer.this
这意味着:
- 内部类可以直接访问外部类的所有成员,包括private字段和方法
java
public class Outer {
private int outerField = 100;
//实例内部类
class Inner {
private int innerField = 200;
public void innerMethod() {
//直接访问外部类私有成员
System.out.println(outerField);
//等同于
System.out.println(Outer.this.outerField);
}
}
}
2.外部类不能直接访问内部类成员
外部类想要访问内部类,必须先创建内部类对象
java
public class Outer {
public int date1 = 1;
//实例内部类
class Inner {
public int innerDate = 2;
}
public void test() {
//System.out.println(innerDate); //不允许的,需要创建内部类对象
Inner inner = new Inner();
System.out.println(inner.innerDate);
}
}
3.不能定义静态成员(static变量/方法)
实例内部类不能有static变量,static方法、static代码块。
因为它依赖外部实例,而static属于类,不依赖实例,两者矛盾
- 访问权限
内部类可以用
- public
- protected
- default(包私有)
- private
private 内部类只能在外部类内部使用。
1.3 如何创建实例内部类对象?
- 在外部类内部创建(简单)
java
public class Outer {
void createInner() {
Inner inner = new Inner();
}
class Inner {}
}
- 在外部类之外创建(必须先有外部对象)
语法格式:
java
Outer outer = new Outer(); //首先得有外部对象
Outer.Inner inner = outer.new Inner(); //然后才用点的方式创建实例内部类对象
完整示例:
java
public class Test {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.innerMethod();
}
}
必须先new Outer(),才能new Inner()
这就是"依附"关系
1.4 内部类如何访问外部类?
内部类可以直接访问外部类所有成员,包括 private。
原理:
编译器会自动给内部类加一个 "隐藏字段":
java
final Outer this$0;
构造 Inner 时,自动把外部对象传进去。
你写的:
java
innerMethod() {
System.out.println(outerField);
}
编译器实际编译成:
java
innerMethod() {
System.out.println(Outer.this.outerField);
}
1.5 同名冲突怎么解决?
如果内部类和外部类有同名成员:
java
class Outer {
int a = 10;
class Inner {
int a = 20;
void test() {
System.out.println(a); // 20(内部类自己)
System.out.println(this.a); // 20
System.out.println(Outer.this.a); // 10(外部类)
}
}
}
规则:
- 直接写变量名 -> 内部类优先
- this.xxx -> 内部类
- 外部类.this.xxx -> 外部类
二、静态内部类
2.1 定义
静态内部类 = 写在别的类里面的普通类,跟外部类只有"包级"关系,不依附外部对象。
用static修饰的成员内部类,就叫静态内部类。
java
public class Outer {
//静态内部类
static class Inner{
}
}
相比于实例内部类:
- 实例内部类(非static):必须寄生在外部对象上
- 静态内部类(static):完全独立,不需要外部对象
2.2 核心特点
1.不持有外部类对象引用
这是和实例内部类最大的区别:
- 实例内部类 -> 有outer.this
- 静态内部类 -> 没有外部引用
2.可以直接new,不需要先new外部类
java
public class Test {
public static void main(String[] args) {
//静态内部类创建方式
Outer.Inner inner = new Outer.Inner();
}
}
相比实例内部类:
java
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
3.只能访问外部类的静态成员
静态内部类里:
- 能访问:外部类的static变量,static方法
- 不能直接访问:外部类的普通成员变量、成员方法
- 如果想要访问外部类普通成员变量和方法,可以先实例外部类对象,通过外部类对象进行调用
java
class Outer {
private static int a = 10;
private int b = 20;
static class Inner {
void test() {
System.out.println(a); // ✅ 可以
System.out.println(b); // ❌ 报错!不能访问外部实例成员
}
}
}
== 4.可以有自己的静态成员==
实例内部类不能有 static,
但静态内部类可以有 static 变量、static 方法。
java
class Outer {
static class Inner {
static int x = 100; // ✅ 允许
static void test() {} // ✅ 允许
}
}
2.3 代码示例
java
public class Outer {
private static String outerStatic = "外部静态变量";
private String outerField = "外部实例变量";
// 静态内部类
public static class Inner {
public void say() {
// 只能访问外部静态成员
System.out.println(outerStatic);
// 下面这句会报错
// System.out.println(outerField);
}
}
}
使用:
java
public class Test {
public static void main(String[] args) {
// 直接创建
Outer.Inner inner = new Outer.Inner();
inner.say();
}
}
2.4 什么时候使用静态内部类?
最常见的场景:
- 某个类只在外部类内部使用,但又不想和外部实例绑定
- 作为数据载体(比如 Builder 模式)
java
Student.builder()
.name("张三")
.age(18)
.build();
这里的 Builder 几乎都是静态内部类。
- 存放常量、工具方法
- 不想单独创建一个 .java 文件,但又需要一个独立类
也就是:
静态内部类就是一个 "住在外部类里面" 的独立类,不依赖外部对象,不持有外部引用,用法跟普通类几乎一样,只是名字要带外部类.
三、局部内部类
3.1 定义
定义在方法里,代码块里、构造方法里的类,就叫局部内部类。
它就像方法里的局部变量,只在这个方法内部有效,外面根本看不见、用不了。
java
public class Outer {
public void test() {
// 👇 这就是局部内部类(写在方法里)
class LocalInner {
public void say() {
System.out.println("我是局部内部类");
}
}
// 只能在方法内部创建对象
LocalInner inner = new LocalInner();
inner.say();
}
public void test2() {
//LocalInner inner = new LocalInner(); //错误,无法识别到这个局部内部类
}
}
特点:
- 只在当前方法里有效
- 外面不能访问,连外部类其他方法都访问不到
- 像局部变量一样,是 "临时的类"
3.2 特点
1.作用域极小
只在当前方法 / 代码块内部有效。
出了这个大括号 {},就不存在了。
2.不能加访问修饰符
局部内部类不能写 public、private、protected、static
因为它本来就是局部的,修饰它没有意义。
java
public void test() {
// 错误写法
public class LocalInner {}
// 正确写法
class LocalInner {}
}
3.可以访问外部类所有成员
包括 private 的变量和方法。
java
public class Outer {
private int a = 100;
public void test() {
class LocalInner {
public void say() {
// 可以直接访问外部类私有成员
System.out.println(a);
}
}
}
}
4.可以访问方法里的局部变量,但必须是 effectively final
JDK 8 以前必须加 final
JDK 8 以后不用写 final,但不能修改,否则报错。
java
public void test() {
int num = 200; // 相当于 final
class LocalInner {
public void say() {
System.out.println(num); // 可以访问
// num = 300; ❌ 报错!不能修改
}
}
}
原因:
局部变量在栈上,方法结束就销毁;
内部类对象在堆上,可能活得更久。
为了安全,Java 强制它不能变。
- 局部内部类里可以定义成员
- 成员变量
- 成员方法
- 甚至再写局部类(没人这么干)
但不能写 static 成员(除了 static final 常量)。
java
class Outer {
private int outerA = 10;
public void method() {
final int localNum = 20; // 局部变量
// 局部内部类
class LocalInner {
private int innerA = 30;
public void test() {
// 访问外部类成员
System.out.println(outerA);
// 访问方法局部变量
System.out.println(localNum);
// 访问自己成员
System.out.println(innerA);
}
}
// 只能在这里创建
LocalInner inner = new LocalInner();
inner.test();
}
}
3.3 三种类比较

3.4 补充
为什么 a = 200; 不能直接写在类里?
java
public class Outer {
private static int a = 10;
private int b = 20;
a = 200; // 这里报错!
}
根本原因:
类 = 定义的地方
方法 / 代码块 = 执行代码的地方
赋值语句 a=200 是执行语句,必须放在方法或代码块里,不能裸写在类中。
Java 类体中,只能写 "定义",不能直接写 "执行语句"
类里面合法的内容只有:
- 成员变量(定义)
- 方法
- 构造器
- 代码块
- 内部类
不能直接写赋值语句、打印语句这种执行代码!
那怎么修改 a 的值?
有 3 种正确写法,任选一种:
方法 1:在方法里修改(最常用)
java
public class Outer {
private static int a = 10;
private int b = 20;
// 写在方法里 ✅
public void change() {
a = 200;
}
}
方法 2:在静态代码块里修改
java
public class Outer {
private static int a = 10;
private int b = 20;
// 静态代码块 ✅
static {
a = 200;
}
}
方法 3:直接定义时赋值
java
private static int a = 200;
所以:
- 类中不能直接写执行语句(赋值、打印等)
- 变量修改必须放在方法或代码块内
- static 变量可以在静态代码块 / 静态方法里修改