Java作业:使用匿名内部类计算方法执行时间
·
一、作业需求 计算一个方法执行了多少秒(或毫秒),要求使用匿名内部类实现。 这是一个典型的应用场景:在不修改原有方法代码的情况下,为方法添加执行时间统计功能。 二、什么是匿名内部类? 2.1 定义 匿名内部类(Anonymous Inner Class)是没有名字的内部类,通常用于**一次性使用**的场景。 2.2 基本语法
匿名内部类语法示例
匿名内部类的标准语法格式如下,适用于直接实现接口或继承父类并重写方法:
父类/接口 变量名 = new 父类/接口() {
@Override
返回类型 方法名(参数列表) {
// 方法实现
}
};
具体实现案例
实现接口示例(Runnable):
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类执行任务");
}
};
继承抽象类示例(Thread):
Thread thread = new Thread() {
@Override
public void run() {
System.out.println("重写Thread的run方法");
}
};
使用场景说明
- 适用于需要一次性使用的类实现,避免单独创建子类文件
- 常用于事件监听、线程实现等需要快速重写方法的场景
- 匿名内部类会隐式持有外部类的引用,需注意内存泄漏问题
语法要点
- 必须实现父类或接口的所有抽象方法
- 可以访问外部类的final变量或等效final变量
- 编译后会生成独立的.class文件,命名格式为
外部类$数字.class
Lambda简化场景
当接口仅含单个抽象方法时(函数式接口),可用Lambda表达式替代:
Runnable task = () -> System.out.println("Lambda替代匿名类");
2.3 特点
| 特点 | 说明 |
|---|---|
| 没有类名 | 创建时直接定义类体 |
| 一次性使用 | 通常只使用一次 |
| 简化代码 | 避免单独定义一个类 |
| 必须实现所有抽象方法 | 与普通类相同 |
三、设计思路
3.1 核心问题
如何在不修改原有方法代码的情况下,统计方法的执行时间?
3.2 解决方案
使用模板方法设计模式 + 匿名内部类:
-
定义一个接口或抽象类,包含需要执行的方法
-
在工具类中编写计时方法,接收接口/抽象类的实现
-
调用时使用匿名内部类传入具体逻辑
3.3 流程图
以下是基于文本描述的计时流程实现方案,采用Java代码示例和流程图说明:
代码实现方案
// 定义函数式接口,便于匿名内部类实现
@FunctionalInterface
interface TargetMethod {
void execute();
}
public class TimeRecorder {
public static void recordExecutionTime(TargetMethod method) {
long startTime = System.nanoTime();
method.execute();
long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println("Execution time: " + duration + " ns");
}
public static void main(String[] args) {
// 通过匿名内部类实现目标方法
recordExecutionTime(new TargetMethod() {
@Override
public void execute() {
// 替换为实际需要计时的代码
int sum = 0;
for (int i = 0; i < 1000000; i++) {
sum += i;
}
}
});
}
}
流程图表示
text
开始计时
↓
记录开始时间 (startTime)
↓
执行目标方法 ←──── 匿名内部类提供具体实现
↓
记录结束时间 (endTime)
↓
计算耗时 = endTime - startTime
↓
输出结果
关键说明
- 时间精度:使用
System.nanoTime()获取纳秒级时间戳,比currentTimeMillis()精度更高 - 函数式接口:通过接口设计使计时逻辑与业务逻辑解耦
- Lambda优化:Java 8+可使用Lambda简化匿名内部类写法:
recordExecutionTime(() -> { int sum = IntStream.range(0, 1000000).sum(); });
注意事项
- 避免在测试方法中包含IO操作或随机因素
- 考虑JVM预热问题,正式测试前应先执行几次预热运行
- 对于微基准测试建议使用JMH等专业框架
四、代码实现
4.1 方式一:使用接口
以下是整理后的代码块格式:
/**
* 定义一个接口,包含需要计时的方法
*/
interface Task {
void execute(); // 需要执行的任务
}
/**
* 计时器工具类
*/
class TimerUtil {
/**
* 计算任务执行时间(毫秒)
* @param task 要执行的任务
*/
public static void measureTime(Task task) {
long startTime = System.currentTimeMillis();
task.execute();
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
System.out.println("方法执行耗时:" + duration + " 毫秒");
System.out.println("转换为秒:" + duration / 1000.0 + " 秒");
}
}
/**
* 测试类
*/
public class TimeTest {
public static void main(String[] args) {
TimerUtil.measureTime(new Task() {
@Override
public void execute() {
System.out.println("开始执行任务...");
for (int i = 0; i < 100000000; i++) {
Math.sqrt(i);
}
System.out.println("任务执行完毕");
}
});
}
}
运行结果:
开始执行任务...
任务执行完毕
方法执行耗时:12 毫秒
转换为秒:0.012 秒
4.2 方式二:使用抽象类
/**
* 抽象类:需要计时的任务
*/
abstract class AbstractTask {
public abstract void run();
}
/**
* 计时器工具类(支持抽象类)
*/
class TimerUtil2 {
public static void measureTime(AbstractTask task) {
long startTime = System.nanoTime(); // 纳秒,更精确
task.run();
long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println("执行耗时:" + duration + " 纳秒");
System.out.println("转换为毫秒:" + duration / 1000000.0 + " 毫秒");
}
}
/**
* 测试类
*/
public class TimeTest2 {
public static void main(String[] args) {
// 使用匿名内部类继承AbstractTask
TimerUtil2.measureTime(new AbstractTask() {
@Override
public void run() {
// 需要计时的业务逻辑
System.out.println("正在计算100以内素数...");
for (int i = 2; i <= 100; i++) {
boolean isPrime = true;
for (int j = 2; j <= Math.sqrt(i); j++) {
if (i % j == 0) {
isPrime = false;
break;
}
}
if (isPrime) {
System.out.print(i + " ");
}
}
System.out.println();
}
});
}
}
4.3 方式三:带返回值的方法计时
如果需要统计的方法有返回值,可以使用泛型:
/**
* 带返回值的任务接口
* @param <T> 返回值类型
*/
interface CallableTask<T> {
T execute();
}
/**
* 计时器工具类(支持返回值)
*/
class TimerUtil3 {
public static <T> T measureTime(CallableTask<T> task, String taskName) {
System.out.println("========== " + taskName + " ==========");
long startTime = System.currentTimeMillis();
T result = task.execute();
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
System.out.println("执行耗时:" + duration + " 毫秒(" + duration / 1000.0 + " 秒)");
System.out.println("================================");
return result;
}
}
/**
* 测试类
*/
public class TimeTest3 {
public static void main(String[] args) {
// 计算1到100的和,并返回结果
Integer sum = TimerUtil3.measureTime(new CallableTask<Integer>() {
@Override
public Integer execute() {
int total = 0;
for (int i = 1; i <= 100; i++) {
total += i;
}
System.out.println("计算结果:" + total);
return total;
}
}, "计算1-100的和");
System.out.println("返回结果:" + sum);
// 计算斐波那契数列
TimerUtil3.measureTime(new CallableTask<Void>() {
@Override
public Void execute() {
System.out.println("斐波那契数列前20项:");
long a = 0, b = 1;
for (int i = 0; i < 20; i++) {
System.out.print(a + " ");
long temp = a + b;
a = b;
b = temp;
}
System.out.println();
return null;
}
}, "斐波那契数列");
}
}
五、多种时间单位说明
| 方法 | 返回单位 | 说明 |
|---|---|---|
System.currentTimeMillis() |
毫秒 | 从1970-01-01到现在的毫秒数 |
System.nanoTime() |
纳秒 | 高精度计时,适合短时间测量 |
以下是将时间单位转换的Java代码示例:
毫秒转秒
long ms = 1234;
double seconds = ms / 1000.0; // 结果为1.234秒
纳秒转毫秒
long ns = 12345678;
double ms = ns / 1000000.0; // 结果为12.345678毫秒
秒转毫秒
double seconds = 1.5;
long ms = (long)(seconds * 1000); // 结果为1500毫秒
毫秒转纳秒
long ms = 15;
long ns = ms * 1000000L; // 结果为15000000纳秒
注意事项:
- 使用浮点数除法(1000.0)确保精度不丢失
- 大数值计算时使用L后缀防止整数溢出
- 从浮点转整型时需要进行显式类型转换
六、不使用匿名内部类的对比
6.1 传统方式(单独定义一个类)
// 需要单独定义一个类
class MyTask implements Task {
@Override
public void execute() {
// 业务逻辑
}
}
// 使用时
TimerUtil.measureTime(new MyTask());
6.2 使用匿名内部类的方式
TimerUtil.measureTime(new Task() {
@Override
public void execute() {
// 业务逻辑
}
});
代码说明
- 使用匿名内部类实现
Task接口 measureTime方法接收Task实例并测量其execute方法的执行时间- 业务逻辑需在
execute方法中实现
格式要点
- 代码块使用三个反引号加语言类型标记
- 保持原代码缩进结构
- 注释保留在原有位置
6.3 Lambda表达式方式(Java 8+)
// 更简洁的Lambda写法(接口只有一个抽象方法时)
TimerUtil.measureTime(() -> {
// 业务逻辑
});
代码说明
- 使用Lambda表达式简化了匿名内部类的写法
- 适用于函数式接口(只有一个抽象方法的接口)
- 大括号内可编写需要计时的业务逻辑代码
- 代码块格式便于在Markdown文档中突出显示
注意事项
- 确保TimerUtil类已正确导入
- measureTime方法需接收Runnable或Callable等函数式接口参数
- Lambda表达式中的业务逻辑不应过于复杂
| 方式 | 代码量 | 可读性 | 适用场景 |
|---|---|---|---|
| 单独定义类 | 多 | 一般 | 需要多处复用 |
| 匿名内部类 | 中 | 较好 | 一次性使用 |
| Lambda | 少 | 好 | 接口只有一个抽象方法 |
七、完整示例:多个方法计时
以下是转换后的代码块格式:
/**
* 综合示例:统计多个排序算法的执行时间
*/
public class SortTimeTest {
public static void main(String[] args) {
// 准备测试数据
int[] arr1 = generateRandomArray(10000);
int[] arr2 = arr1.clone();
// 测试冒泡排序时间
TimerUtil.measureTime(new Task() {
@Override
public void execute() {
bubbleSort(arr1.clone());
System.out.println("冒泡排序完成");
}
});
// 测试快速排序时间
TimerUtil.measureTime(new Task() {
@Override
public void execute() {
quickSort(arr2.clone(), 0, arr2.length - 1);
System.out.println("快速排序完成");
}
});
}
/**
* 生成随机数组
*/
private static int[] generateRandomArray(int size) {
int[] arr = new int[size];
for (int i = 0; i < size; i++) {
arr[i] = (int) (Math.random() * size);
}
return arr;
}
/**
* 冒泡排序
*/
private static void bubbleSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
/**
* 快速排序
*/
private static void quickSort(int[] arr, int left, int right) {
if (left >= right) return;
int pivot = partition(arr, left, right);
quickSort(arr, left, pivot - 1);
quickSort(arr, pivot + 1, right);
}
private static int partition(int[] arr, int left, int right) {
int pivot = arr[left];
int i = left, j = right;
while (i < j) {
while (i < j && arr[j] >= pivot) j--;
arr[i] = arr[j];
while (i < j && arr[i] <= pivot) i++;
arr[j] = arr[i];
}
arr[i] = pivot;
return i;
}
}
八、总结
8.1 核心知识点
| 知识点 | 应用 |
|---|---|
| 匿名内部类 | 简化代码,一次性传入任务逻辑 |
| 接口/抽象类 | 定义任务规范 |
| System.currentTimeMillis() | 获取系统时间,计算耗时 |
| 模板方法模式 | 固定计时流程,任务逻辑可变 |
8.2 匿名内部类的使用场景
-
回调函数:如本作业的方法计时
-
事件监听:GUI编程中的按钮点击事件
-
线程创建:
new Thread(new Runnable() {...}) -
集合排序:
Collections.sort(list, new Comparator() {...})
8.3 作业完成情况
-
实现了方法执行时间计算功能
-
使用了匿名内部类
-
支持毫秒/纳秒两种精度
-
支持带返回值的场景
更多推荐


所有评论(0)