75. Java 嵌套类 - 匿名类

125 阅读4分钟

75. Java 嵌套类 - 匿名类

在 Java 开发中,我们经常会写一些 一次性 使用的类,比如:

  • 实现一个接口
  • 扩展一个类
  • 只需要在某个方法里使用一次

如果用普通类来写,这样的代码会很冗长。所以,Java 提供了一种 更简洁的方式 —— 匿名类(Anonymous Class)


什么是匿名类(Anonymous Classes)?

匿名类和 局部类(Local Class) 很像,但它没有名字! 换句话说,它只在声明它的地方创建,不需要单独的类名

匿名类的特点

只使用一次:适用于临时对象,不需要重复使用的类。 ✅ 没有类名:在声明的同时 进行 实例化。 ✅ 可以实现接口,也可以继承类。 ✅ 不能有构造方法(但可以有实例初始化块)。


匿名类 vs. 局部类

特性局部类(Local Class)匿名类(Anonymous Class)
是否有名字✅ 有❌ 没有
作用范围只能在定义它的方法/代码块内使用只能在创建它的那一行代码中使用
代码量相对较多(需要先定义类,再创建对象)更简洁(直接在实例化时定义)
适用场景可能会多次使用的辅助类只用一次的小型逻辑实现

示例 1:用匿名类实现接口

来看一个例子:我们要实现一个 HelloWorld 接口,并创建不同语言的问候。

代码

public class HelloWorldAnonymousClasses {

    interface HelloWorld {
        void greet();
        void greetSomeone(String someone);
    }

    public void sayHello() {

        // 普通局部类实现
        class EnglishGreeting implements HelloWorld {
            String name = "world";

            public void greet() {
                greetSomeone("world");
            }

            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Hello " + name);
            }
        }
        HelloWorld englishGreeting = new EnglishGreeting(); // 使用局部类

        // 匿名类实现(French)
        HelloWorld frenchGreeting = new HelloWorld() {
            String name = "tout le monde";

            public void greet() {
                greetSomeone("tout le monde");
            }

            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Salut " + name);
            }
        };

        // 匿名类实现(Spanish)
        HelloWorld spanishGreeting = new HelloWorld() {
            String name = "mundo";

            public void greet() {
                greetSomeone("mundo");
            }

            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Hola, " + name);
            }
        };

        englishGreeting.greet();
        frenchGreeting.greetSomeone("Fred");
        spanishGreeting.greet();
    }

    public static void main(String... args) {
        HelloWorldAnonymousClasses myApp = new HelloWorldAnonymousClasses();
        myApp.sayHello();
    }
}

运行结果

Hello world
Salut Fred
Hola, mundo

代码解析

1️⃣ 局部类 EnglishGreeting

  • 这个类有一个 name 变量,默认值是 "world"
  • greet() 方法会调用 greetSomeone("world")
  • greetSomeone(String someone) 方法可以修改 name,然后打印问候语。

2️⃣ 匿名类 frenchGreetingspanishGreeting

  • 没有类名,直接在 创建对象时 定义类的实现。
  • 实现了 HelloWorld 接口,但写法更加简洁。
  • 直接在实例化的时候实现接口里的方法

匿名类的语法

HelloWorld frenchGreeting = new HelloWorld() {
    String name = "tout le monde";

    public void greet() {
        greetSomeone("tout le monde");
    }

    public void greetSomeone(String someone) {
        name = someone;
        System.out.println("Salut " + name);
    }
};

匿名类表达式的组成

语法部分作用
new创建新对象
HelloWorld()实现的接口(或继承抽象类
{}匿名类的类体(这里定义了变量和方法)

关键点:

  • 接口不能有构造方法,所以这里的 () 是空的。
  • 匿名类的类体 里可以有 实例变量方法

匿名类 vs. 继承类

匿名类不仅可以 实现接口,还能 继承类

示例 2:匿名类继承抽象类

abstract class Animal {
    abstract void makeSound();
}

public class AnonymousClassExample {
    public static void main(String[] args) {
        Animal dog = new Animal() {
            public void makeSound() {
                System.out.println("Woof Woof!");
            }
        };

        dog.makeSound(); // 输出:Woof Woof!
    }
}

这里的 dog 对象

  • 继承了 Animal 类,但没有给它起名字
  • 直接在创建 dog 对象时,重写了 makeSound() 方法。

匿名类的局限

尽管匿名类很方便,但它也有一些限制: ❌ 不能有构造方法(但可以有实例初始化块)。 ❌ 不能有 static 方法或变量(除了 static final 常量)。 ❌ 只能使用一次,如果需要多次使用,应该使用 普通类局部类

示例 3:匿名类不能有 static 方法

public class Test {
    public static void main(String[] args) {
        Animal dog = new Animal() {
            static void staticMethod() {  // ❌ 错误:匿名类不能有 static 方法
                System.out.println("This won't compile!");
            }
            public void makeSound() {
                System.out.println("Woof Woof!");
            }
        };
    }
}

编译错误

修饰符 static 仅在常量变量声明中允许

适用场景

适合用匿名类的情况

  • 只需要用 一次 的类,例如 事件监听器回调函数临时实现
  • 需要 快速实现接口,但不想写单独的类文件。

不适合用匿名类的情况

  • 代码逻辑比较复杂,需要 多次使用(建议改成 普通类)。
  • 需要 构造方法或静态方法(匿名类不支持)。
  • 需要定义 多个方法(局部类更适合)。

总结

特点匿名类
作用一次性使用
是否有名字❌ 没有
是否能有构造方法❌ 不能(但可以有实例初始化块)
是否能有 static 方法❌ 不能
适用于简短的接口实现或类扩展

希望这次讲解能让你更清楚 匿名类的用法和局限!🚀 🎯