java:匿名类(匿名内部类)

一、场景引入

想象这个场景:你需要临时使用一个接口或父类的某个方法,但只想用一次。

传统做法

// People接口
interface People {
    void eat();
}
// 写一个实现类Student实现接口People
public class Student implements People{
    @Override
    public void eat(){
        System.out.println("正在吃东西...");
    }
}
// main类中创建student对象,调用eat
public class Main {
    public static void main(String[] args) {
        Student student = new Student();
        student.eat();
    }
}

为了一个简单的方法调用,需要额外创建一个类文件,既麻烦又让代码变得冗长。

匿名内部类解决方案

// People接口
interface People {
    void eat();
}
public class Main {
    public static void main(String[] args) {

        // 使用匿名内部类实现People接口
        People person = new People() {
            @Override
            public void eat() {
                System.out.println("正在吃东西...");
            }

        };
        
        // 调用接口方法
        person.eat(); // 输出: 正在吃东西...
    }
}

        它的语法如下

二、什么是匿名内部类

        匿名内部类是没有名字的内部类,它在声明的同时就创建了唯一的一个对象。由于Java不允许外部类没有名字,所以匿名类一定是内部类。

核心特性

  • 🚫 没有类名

  • 🎯 随声明随创建,只有这一个对象

  • 🔒 无法重复使用,专为一次性场景设计

三、基本特点

1. 必须基于一个父类或接口

写法如下

// 必须继承类或实现接口
父类/接口 变量名 = new 父类/接口() {
    // 实现或重写方法
};

2. 即声明即使用

// 声明时直接创建对象,立即可用
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("线程运行中");
    }
});
thread.start();

四、使用场景

1. 事件监听器(最常用) 🎯

在GUI编程中,匿名内部类广泛用于事件处理:

// Swing GUI中的按钮点击事件
JButton button = new JButton("点击我");
button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("按钮被点击了!");
        // 处理点击事件的逻辑
    }
});

// Android开发中的点击事件
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 处理点击事件
    }
});

2. 多线程实现

创建线程时使用Runnable接口:

// 创建并启动新线程
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        // 线程执行的代码
        for (int i = 0; i < 5; i++) {
            System.out.println("线程执行: " + i);
        }
    }
});
thread.start();

3. 集合排序和比较 📊

使用Comparator进行自定义排序:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");

// 使用匿名内部类按字符串长度排序
Collections.sort(names, new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        return s1.length() - s2.length();
    }
});

// 或者使用匿名内部类按字母顺序逆序排序
names.sort(new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        return s2.compareTo(s1);
    }
});

4. 回调函数 🔄

在各种框架和库中处理回调:

// 模拟一个异步操作的回调
public void fetchData(Callback callback) {
    // 模拟网络请求
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(1000); // 模拟延迟
                callback.onSuccess("数据获取成功");
            } catch (InterruptedException e) {
                callback.onError(e);
            }
        }
    }).start();
}

// 使用匿名内部类实现回调接口
fetchData(new Callback() {
    @Override
    public void onSuccess(String data) {
        System.out.println("成功: " + data);
    }
    
    @Override
    public void onError(Exception e) {
        System.err.println("错误: " + e.getMessage());
    }
});

5. 工厂方法模式 🏭

在需要快速创建对象实例时:

// 创建不同类型的动物
interface Animal {
    void speak();
}

class AnimalFactory {
    public static Animal createAnimal(final String type) {
        return new Animal() {
            @Override
    `        public void speak() {
                if ("dog".equals(type)) {
                    System.out.println("汪汪!");
                } else if ("cat".equals(type)) {
                    System.out.println("喵喵!");
                }
            }
        };
    }
}

6. 测试代码 🧪

在单元测试中快速创建测试对象:

@Test
public void testWithAnonymousClass() {
    // 快速创建一个接口的测试实现
    UserService mockService = new UserService() {
        @Override
        public User findUserById(int id) {
            return new User(id, "测试用户");
        }
        
        @Override
        public boolean saveUser(User user) {
            return true;
        }
    };
    
    // 使用mock对象进行测试
    User user = mockService.findUserById(1);
    assertEquals("测试用户", user.getName());
}

为什么这些场景常用?

  1. 简洁性:避免为只使用一次的类创建单独的类文件

  2. 封装性:相关代码集中在一起,提高可读性

  3. 便利性:快速实现,特别适合简单的功能

  4. 上下文感知:可以直接访问外部类的成员变量和方法

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值