Skip to content

匿名内部类

「我只想在这里用一次这个接口的实现,还要单独写一个类?」

匿名内部类就是来解决这个问题的——没有名字,用完即弃。

基本语法

java
public class AnonymousBasicDemo {

    interface Greeting {
        void sayHello();
    }

    public static void main(String[] args) {
        // 匿名内部类:直接 new 接口 + 实现
        Greeting greeting = new Greeting() {
            @Override
            public void sayHello() {
                System.out.println("Hello!");
            }
        };

        greeting.sayHello();
    }
}

实现接口 vs 继承抽象类

实现接口

java
abstract class Animal {
    abstract void makeSound();
}

public class AnonymousExtendDemo {
    public static void main(String[] args) {
        // 匿名内部类继承抽象类
        Animal dog = new Animal() {
            @Override
            void makeSound() {
                System.out.println("Woof!");
            }
        };

        dog.makeSound();
    }
}

带构造参数

匿名内部类没有名字,怎么传构造参数?答案是通过实例初始化块:

java
public class AnonymousWithInitDemo {

    static abstract class Config {
        abstract String getValue();
    }

    public static void main(String[] args) {
        Config config = new Config() {
            private String name = "my-config";
            private int timeout = 30;

            {
                // 实例初始化块,可以做初始化逻辑
                System.out.println("Config initialized");
            }

            @Override
            public String getValue() {
                return name + ":" + timeout;
            }
        };

        System.out.println(config.getValue());
    }
}

Lambda 简化(JDK 8+)

如果是函数式接口(只有一个抽象方法的接口),可以用 Lambda 进一步简化:

java
public class LambdaComparison {

    interface Calculator {
        int calculate(int a, int b);
    }

    public static void main(String[] args) {
        // 匿名内部类
        Calculator add1 = new Calculator() {
            @Override
            public int calculate(int a, int b) {
                return a + b;
            }
        };

        // Lambda 表达式
        Calculator add2 = (a, b) -> a + b;

        // Lambda + 方法引用
        Calculator add3 = Integer::sum;

        System.out.println(add1.calculate(1, 2)); // 3
        System.out.println(add2.calculate(1, 2)); // 3
        System.out.println(add3.calculate(1, 2)); // 3
    }
}

实际应用场景

线程创建

java
public class ThreadAnonymousDemo {

    public static void main(String[] args) {
        // 匿名内部类
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Thread running");
            }
        });

        // Lambda 简化
        Thread t2 = new Thread(() -> System.out.println("Thread running"));

        t1.start();
        t2.start();
    }
}

集合排序

java
import java.util.*;

public class SortAnonymousDemo {

    public static void main(String[] args) {
        List<String> list = Arrays.asList("Java", "Python", "Go", "Rust");

        // 匿名内部类
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String s1, String s2) {
                return s2.length() - s1.length();
            }
        });

        // Lambda 简化
        list.sort((s1, s2) -> s2.length() - s1.length());

        // Comparator 组合
        list.sort(Comparator.comparingInt(String::length).reversed());

        System.out.println(list);
    }
}

注意事项

  1. 没有名字:匿名内部类没有类名,不能有构造方法
  2. 一次性:每个匿名内部类都是独立的类,只创建一个实例
  3. 简化条件:必须是函数式接口才能用 Lambda 替代
  4. 调试困难:匿名内部类的堆栈跟踪不够直观
  5. 适度使用:如果逻辑复杂或需要复用,还是应该用命名类

基于 VitePress 构建