匿名内部类的使用场景
在 Java 开发中,匿名内部类是一种特殊的局部内部类,它没有显式的类名,通常用于简化代码、快速实现接口或继承抽象类。下面我们结合计算方法执行耗时这个经典场景,来讲解匿名内部类的核心用法与示例。
一、匿名内部类的核心概念
匿名内部类本质上是继承一个父类或实现一个接口的匿名子类对象,它的语法格式为:
java
运行
new 父类/接口() {
// 实现抽象方法或重写父类方法
};
它的核心特点是:
没有类名,定义和实例化同时完成;
必须继承一个类或实现一个接口;
只能创建一个实例对象,且只能使用一次;
可以访问外部类的成员变量和局部变量(JDK 1.8 后支持访问非 final 局部变量,但本质仍是隐式 final)。
二、典型场景:计算方法执行耗时
在开发中,我们经常需要统计一段代码的执行时间,使用匿名内部类可以实现代码的解耦,避免为了一次性的功能创建单独的类。
1. 定义一个通用的耗时统计接口
java
运行
// 定义一个函数式接口,代表需要执行的任务
public interface Task {
void execute();
}
2. 编写通用的耗时统计工具方法
java
运行
public class TimeUtils {
// 接收一个Task接口对象,统计其execute方法的执行耗时
public static void countTime(Task task) {
long start = System.currentTimeMillis();
// 执行任务
task.execute();
long end = System.currentTimeMillis();
// 计算耗时并打印
System.out.println("方法执行耗时:" + (end - start) + " 毫秒");
}
}
3. 使用匿名内部类实现任务并统计耗时
java
运行
public class AnonymousInnerClassDemo {
public static void main(String[] args) {
// 场景1:统计循环打印的耗时
TimeUtils.countTime(new Task() {
@Override
public void execute() {
for (int i = 0; i < 10000; i++) {
System.out.print(i);
}
}
});
// 场景2:统计数组排序的耗时
int[] arr = {5, 2, 8, 1, 9, 3, 7, 4, 6};
TimeUtils.countTime(new Task() {
@Override
public void execute() {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
});
}
}
4. 运行结果示例
plaintext
0123456...9999方法执行耗时:12 毫秒
方法执行耗时:0 毫秒
三、其他常见使用场景
除了耗时统计,匿名内部类还有很多高频使用场景:
1. 事件监听器(Swing/Android 开发)
在 GUI 开发中,匿名内部类常用于快速实现事件监听接口,无需创建单独的监听类。
java
运行
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ListenerDemo {
public static void main(String[] args) {
JFrame frame = new JFrame("匿名内部类监听示例");
JButton button = new JButton("点击我");
// 使用匿名内部类实现ActionListener接口
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(frame, "按钮被点击了!");
}
});
frame.add(button);
frame.setSize(300, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
2. 线程任务快速实现
实现 Runnable 接口创建线程时,使用匿名内部类可以简化代码,避免定义单独的线程类。
java
运行
public class ThreadDemo {
public static void main(String[] args) {
// 方式1:继承Thread类的匿名内部类
new Thread() {
@Override
public void run() {
System.out.println("继承Thread的匿名内部类线程执行了");
}
}.start();
// 方式2:实现Runnable接口的匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("实现Runnable的匿名内部类线程执行了");
}
}).start();
}
}
3. 临时的 Comparator 比较器
在集合排序中,使用匿名内部类实现 Comparator 接口,可以为特定场景快速定义排序规则。
java
运行
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class ComparatorDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("apple");
list.add("banana");
list.add("cherry");
// 使用匿名内部类实现Comparator,按字符串长度降序排序
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.length() - o1.length();
}
});
System.out.println("排序后的列表:" + list);
}
}
四、匿名内部类的优缺点
优点
代码简洁,无需为一次性使用的功能创建单独的类;
可以直接访问外部类的成员变量和局部变量;
适合快速实现接口或抽象类的场景。
缺点
可读性较差,当匿名内部类逻辑复杂时,代码难以维护;
不能定义构造方法,也不能使用 static 修饰的成员;
只能创建一个实例,无法复用。
五、与 Lambda 表达式的对比
JDK 1.8 引入 Lambda 表达式后,匿名内部类的很多场景被替代,例如上面的耗时统计、线程、比较器场景,都可以用 Lambda 简化:
java
运行
// Lambda实现耗时统计
TimeUtils.countTime(() -> {
for (int i = 0; i < 10000; i++) {
System.out.print(i);
}
});
// Lambda实现线程
new Thread(() -> System.out.println("Lambda线程执行了")).start();
Lambda 表达式比匿名内部类更简洁,但匿名内部类依然在需要重写多个方法、或需要访问类成员变量的复杂场景中使用。
以上就是匿名内部类的常见使用场景与示例代码,希望能帮助你理解并灵活运用匿名内部类