大多数情况下,Java 中的类被定义为一个独立的程序单元。但在某些情况下,也可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类(也称嵌套类),包含内部类的类也被称为外部类

内部类包括 4 种,分别是成员内部类局部内部类静态内部类匿名内部类。一般情况下,内部类有如下属性:

  • 内部类和外部类由 Java 编译器编译后生成的两个类是独立的;
  • 内部类是外部类的一个成员,可以使用外部类的类变量和实例变量,也可以使用外部类的局部变量;
  • 内部类可以被 protected 或 private 修饰。当一个类中嵌套另一个类时,访问保护并不妨碍内部类使用外部类的成员;
  • 内部类被 static 修饰后,不能再使用局部范围中或其他内部类中的数据和变量。

Java 成员内部类

成员内部类是最普通的内部类,它定义于另一个类的内部,与外部类的成员变量、成员方法同级。

核心特性

  • 成员内部类可以访问外部类的所有成员(包括私有成员);
  • 外部类访问成员内部类需通过实例;
  • 成员内部类依附外部类存在,创建成员内部类对象前必须存在外部类对象。

实例化语法

外部类名.内部类名 引用变量名 = new 外部类名().new 内部类名();

代码示例

class Outer { // 定义外部类
    private String name = "外部类Outer";
    private int num = 666;

    class Inner { // 定义成员内部类
        private String name = "内部类Inner";

        public void accessOuter() {
            System.out.println("在成员内部类中访问内部类的name: " + name);
            System.out.println("在成员内部类中访问外部类的name: " + Outer.this.name); // Outer.this 表示外部类对象
            System.out.println("在成员内部类中访问外部类的num: " + num);
        }
    }
}

public class Demo {
    public static void main(String[] args) {
        Outer.Inner inner = new Outer().new Inner(); // 实例化成员内部类
        inner.accessOuter();
    }
}

运行结果

在成员内部类中访问内部类的name: 内部类Inner
在成员内部类中访问外部类的name: 外部类Outer
在成员内部类中访问外部类的num: 666

注意事项

  • 成员内部类不能定义静态变量、静态方法和静态内部类
  • 内部类与外部类成员变量重名时,需通过 Outer.this.变量名 访问外部类成员。

Java 局部内部类

局部内部类是指在成员方法中定义的类,作用域仅限于该方法或代码块内。

核心特性

  • 对外部类完全隐藏,仅在定义它的方法内可见;
  • 不能使用访问修饰符(publicprivateprotected);
  • 可访问外部类所有成员,但只能访问方法中 final 或隐式 final 的局部变量(JDK 8+ 自动添加 final)。

代码示例

class Outer { // 定义外部类
    private static String name = "外部类Outer";
    private int num = 666;

    public void display() {
        int count = 5; // 隐式 final(JDK 8+)

        class Inner { // 局部内部类
            public void accessOuter() {
                System.out.println("在局部内部类中访问外部方法的变量: " + count);
                System.out.println("在局部内部类中访问外部类的name: " + Outer.name);
                System.out.println("在局部内部类中访问外部类的num: " + num);
            }
        }

        new Inner().accessOuter(); // 仅在方法内可用
    }
}

public class Demo {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.display();
    }
}

运行结果

在局部内部类中访问外部方法的变量: 5
在局部内部类中访问外部类的name: 外部类Outer
在局部内部类中访问外部类的num: 666

注意事项

  • 局部变量若在内部类中使用,不能修改(因隐式 final);
  • 局部内部类不可在外部类其他方法中使用

Java 静态内部类

静态内部类是指用 static 关键字修饰的成员内部类,不依赖外部类实例

核心特性

  • 可直接通过外部类名实例化,无需外部类对象;
  • 仅能访问外部类的静态成员(类变量、类方法);
  • 可定义静态成员和非静态成员。

实例化语法

外部类名.内部类名 引用变量名 = new 外部类名.内部类名();

代码示例

class Outer {
    private static String name = "外部类Outer"; // 静态成员
    private static int num = 666;

    static class Inner { // 静态内部类
        public static String innerName = "内部类Inner"; // 静态成员

        public void accessOuter() {
            System.out.println("在静态内部类中访问外部类的name: " + Outer.name);
            System.out.println("在静态内部类中访问外部类的num: " + num);
        }
    }
}

public class Demo {
    public static void main(String[] args) {
        // 访问静态成员
        System.out.println("静态内部类静态成员: " + Outer.Inner.innerName);

        // 实例化静态内部类
        Outer.Inner obj = new Outer.Inner();
        obj.accessOuter();
    }
}

运行结果

静态内部类静态成员: 内部类Inner
在静态内部类中访问外部类的name: 外部类Outer
在静态内部类中访问外部类的num: 666

注意事项

  • 静态内部类不能直接访问外部类非静态成员
  • 静态内部类独立性强,类似 “顶级类”,常用于封装工具类或数据结构(如 Map.Entry)。

Java 匿名内部类

匿名内部类是一个没有显式名字的内部类,本质是隐式继承类或实现接口的子类对象。

核心特性

  • 必须继承一个类或实现一个接口;
  • 无构造方法,无类名,仅能使用一次;
  • 常用于事件监听、回调等一次性逻辑

语法格式

new 类名/接口名/抽象类名() {
    // 匿名内部类实现(重写方法)
}

代码示例(实现接口)

interface Inner {
    void getName(String name);
}

public class Demo {
    public static void main(String[] args) {
        // 匿名内部类实现接口
        new Inner() {
            @Override
            public void getName(String name) {
                System.out.println("我是匿名类的方法,获取name为:" + name);
            }
        }.getName("张三"); // 直接调用方法
    }
}

运行结果

我是匿名类的方法,获取name为:张三

注意事项

  • 匿名内部类不能定义静态成员
  • 复杂逻辑(超过 4 行)建议改用具名类,避免代码臃肿。

总结对比

类型 定义位置 依赖外部类实例 访问外部成员 静态成员支持 实例化方式
成员内部类 外部类成员位置 所有成员 仅静态常量(JDK 16+) new 外部类().new 内部类()
局部内部类 方法 / 代码块内 所有成员 + 最终局部变量 不支持 仅在定义范围内实例化
静态内部类 外部类成员位置 仅静态成员 支持 new 外部类.内部类()
匿名内部类 表达式中 是(非静态) 所有成员 + 最终局部变量 不支持 new 父类/接口() { ... }

更多推荐