Java 匿名内部类简明指南(重点)

📌 匿名内部类是什么?

没有名字的内部类,在创建对象的同时定义类体。

🎯 一句话理解

直接 new 接口或类,并立即实现/重写方法

💡 基本语法

1. 实现接口

java 复制代码
// 接口
interface Animal {
    void makeSound();
}

public class Demo {
    public static void main(String[] args) {
        // 匿名内部类:直接new接口
        Animal dog = new Animal() {
            @Override
            public void makeSound() {
                System.out.println("汪汪!");
            }
        };
        
        dog.makeSound();  // 输出:汪汪!
    }
}

2. 继承抽象类

java 复制代码
// 抽象类
abstract class Person {
    abstract void speak();
    void breathe() {
        System.out.println("呼吸中...");
    }
}

public class Demo {
    public static void main(String[] args) {
        // 匿名内部类:继承抽象类
        Person student = new Person() {
            @Override
            void speak() {
                System.out.println("我是学生");
            }
            
            // 可以重写父类方法
            @Override
            void breathe() {
                super.breathe();
                System.out.println("学生呼吸");
            }
        };
        
        student.speak();    // 输出:我是学生
        student.breathe();  // 输出:呼吸中... 学生呼吸
    }
}

3. 继承普通类

java 复制代码
// 普通类
class Printer {
    void print(String msg) {
        System.out.println("打印: " + msg);
    }
}

public class Demo {
    public static void main(String[] args) {
        // 匿名内部类:继承普通类
        Printer colorPrinter = new Printer() {
            @Override
            void print(String msg) {
                System.out.println("彩色打印: " + msg);
            }
            
            // 可以添加新方法(但外部不能调用)
            void scan() {
                System.out.println("扫描功能");
            }
        };
        
        colorPrinter.print("文档");  // 输出:彩色打印: 文档
        // colorPrinter.scan();     // ❌ 编译错误
    }
}

🚀 实际应用场景

场景1:事件监听(最常用)

java 复制代码
// 点击监听接口
interface OnClickListener {
    void onClick();
}

// 按钮类
class Button {
    private OnClickListener listener;
    
    void setOnClickListener(OnClickListener listener) {
        this.listener = listener;
    }
    
    void click() {
        if (listener != null) {
            listener.onClick();
        }
    }
}

public class EventDemo {
    public static void main(String[] args) {
        Button button = new Button();
        
        // 使用匿名内部类设置点击事件
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick() {
                System.out.println("按钮被点击了!");
                System.out.println("执行操作...");
            }
        });
        
        button.click();  // 输出:按钮被点击了!执行操作...
    }
}

场景2:线程创建

java 复制代码
public class ThreadDemo {
    public static void main(String[] args) {
        // 创建线程(传统方式)
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程1运行中");
            }
        });
        
        // Java 8+:Lambda表达式(更简洁)
        Thread thread2 = new Thread(() -> {
            System.out.println("线程2运行中");
        });
        
        thread1.start();
        thread2.start();
    }
}

场景3:集合排序

java 复制代码
import java.util.*;

public class SortDemo {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("张三", "李四", "王五");
        
        // 使用匿名内部类进行自定义排序
        Collections.sort(names, new Comparator<String>() {
            @Override
            public int compare(String a, String b) {
                // 按字符串长度排序
                return Integer.compare(a.length(), b.length());
            }
        });
        
        System.out.println("排序后: " + names);
        
        // Java 8+:Lambda表达式
        Collections.sort(names, (a, b) -> b.length() - a.length());
        System.out.println("反向排序: " + names);
    }
}

🔑 核心特点

1. 没有类名

java 复制代码
interface Greeting {
    void sayHello();
}

public class Demo {
    public static void main(String[] args) {
        // 这里没有类名,直接new接口
        Greeting greeting = new Greeting() {
            @Override
            public void sayHello() {
                System.out.println("你好!");
            }
            
            // 这个类没有名字,无法在其他地方使用
        };
    }
}

2. 只能使用一次

java 复制代码
interface Calculator {
    int calculate(int a, int b);
}

public class Demo {
    public static void main(String[] args) {
        // 创建加法计算器(只能用这一次)
        Calculator adder = new Calculator() {
            @Override
            public int calculate(int a, int b) {
                return a + b;
            }
        };
        
        System.out.println("5 + 3 = " + adder.calculate(5, 3));
        
        // 如果需要乘法,必须再创建一个
        Calculator multiplier = new Calculator() {
            @Override
            public int calculate(int a, int b) {
                return a * b;
            }
        };
        
        System.out.println("5 * 3 = " + multiplier.calculate(5, 3));
    }
}

3. 访问外部变量(必须是final)

java 复制代码
public class VariableDemo {
    public static void main(String[] args) {
        final String message = "Hello";  // 必须是final
        
        Runnable task = new Runnable() {
            @Override
            public void run() {
                // 可以访问final局部变量
                System.out.println(message);
                
                // 不能修改(因为实际上是final)
                // message = "Hi";  // ❌ 编译错误
            }
        };
        
        new Thread(task).start();
    }
}

⚡ 匿名内部类 vs Lambda表达式

对比示例

java 复制代码
interface MathOperation {
    int operate(int a, int b);
}

public class CompareDemo {
    public static void main(String[] args) {
        // 匿名内部类写法
        MathOperation add1 = new MathOperation() {
            @Override
            public int operate(int a, int b) {
                return a + b;
            }
        };
        
        // Lambda表达式写法(Java 8+)
        MathOperation add2 = (a, b) -> a + b;
        
        System.out.println("匿名内部类: " + add1.operate(5, 3));
        System.out.println("Lambda: " + add2.operate(5, 3));
    }
}

使用选择

markdown 复制代码
问:用匿名内部类还是Lambda?

1. 接口只有一个抽象方法?
   - 是 → 用Lambda表达式 ✅(更简洁)
   - 否 → 用匿名内部类

2. 需要重写多个方法?
   - 是 → 用匿名内部类
   - 否 → 用Lambda

3. 需要访问外部类的非final变量?
   - 是 → 用匿名内部类(Lambda要求final)
   - 否 → 用Lambda

总结:
- 简单情况:用Lambda
- 复杂情况:用匿名内部类

💎 实用技巧

1. 方法参数直接使用

java 复制代码
interface Validator {
    boolean validate(String input);
}

class Form {
    void submit(Validator validator) {
        // 使用传入的验证器
        if (validator.validate("test")) {
            System.out.println("验证通过");
        }
    }
}

public class ParamDemo {
    public static void main(String[] args) {
        Form form = new Form();
        
        // 直接在参数中使用匿名内部类
        form.submit(new Validator() {
            @Override
            public boolean validate(String input) {
                return input != null && input.length() > 0;
            }
        });
    }
}

2. 一次性任务

java 复制代码
public class OneTimeTask {
    public static void main(String[] args) {
        // 一次性任务:文件处理
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("开始处理文件...");
                // 处理逻辑
                System.out.println("文件处理完成");
            }
        }).start();
    }
}

⚠️ 注意事项

  1. 没有构造器:不能定义构造方法
  2. 不能有静态成员:不能有static方法和变量
  3. 只能继承一个类或实现一个接口
  4. 代码可读性:复杂的匿名内部类影响可读性

📝 记忆口诀

markdown 复制代码
匿名内部类三要素:
1. new 接口/类
2. 立即实现/重写方法
3. 没有类名,只能用一次

使用场景:
1. 事件监听
2. 线程创建
3. 临时实现
4. 参数传递

🎯 一句话总结

匿名内部类就是"即用即丢"的临时实现,适合简单的一次性任务。复杂情况还是用正常类。

相关推荐
czlczl200209251 小时前
SpringBoot手动配置:WebMvcConfigurer接口实现类的生效原理
java·spring boot·后端
程序员皮皮林1 小时前
SpringBoot + nmap4j 获取端口信息
java·spring boot·后端
小二·1 小时前
Spring框架入门:Spring 中注解支持详解
java·后端·spring
计算机学长felix1 小时前
基于SpringBoot的“某学院教室资产管理系统”的设计与实现(源码+数据库+文档+PPT)
数据库·spring boot·后端
百花~1 小时前
Spring IoC&DI~
java·后端·spring
卷到起飞的数分1 小时前
20.Spring Boot原理2
java·spring boot·后端
申阳1 小时前
Day 20:开源个人项目时的一些注意事项
前端·后端·程序员
shepherd1111 小时前
一文带你掌握MyBatis-Plus代码生成器:从入门到精通,实现原理与自定义模板全解析
java·spring boot·后端
sivdead1 小时前
Agent平台消息节点输出设计思路
后端·python·agent