全网最通俗、最清晰对比:
<T> T execute(...) 泛型方法 VS TaskExecutor<T> 泛型接口
用最简单的人话讲透,看完再也不会混淆!
一、先看两段代码
1️⃣ 泛型方法
java
public interface TaskExecutor {
<T> T execute(Task<T> task);
}
特点:接口没有泛型,方法自己带泛型 <T>
2️⃣ 泛型接口
java
public interface TaskExecutor<T> {
T execute(Task<T> task);
}
特点:接口带泛型,方法没有 <T>
二、核心区别
✅ 1. 泛型方法:一个执行器,可以执行所有类型任务
<T> T execute(...)
- 一个执行器 → 万能通用
- 可以同时执行:
Task<String>Task<Integer>Task<User>- 任何类型
- T 是每次调用方法时动态确定的
❌ 2. 泛型接口:一个执行器只能执行一种固定类型
TaskExecutor<T>
- 创建时就固定死 T
- 例如:
TaskExecutor<String>→ 只能执行 String 任务TaskExecutor<Integer>→ 只能执行 Integer 任务
- T 是创建类时确定,整个类都用同一个 T
三、超级通俗比喻
1️⃣ 泛型方法 = 万能充电器
一个充电器,能充:
- 苹果手机
- 安卓手机
- 耳机
- 充电宝
你传什么,它就充什么。
2️⃣ 泛型接口 = 专用充电器
买的时候就决定:
- 只充苹果手机
- 别的都不能用
四、代码对比
【泛型方法】
java
TaskExecutor executor = new SyncTaskExecutor();
// 同一个执行器,可以执行任意类型!!!
String s = executor.execute(new PrintTask("test"));
Integer i = executor.execute(new NumberTask(100));
User u = executor.execute(new UserTask(user));
【泛型接口】
java
TaskExecutor<String> stringExecutor = new SyncTaskExecutor<>();
stringExecutor.execute(task); // 只能返回 String
TaskExecutor<Integer> intExecutor = new SyncTaskExecutor<>();
intExecutor.execute(task); // 只能返回 Integer
必须创建多个执行器,非常麻烦!
五、为什么用【泛型方法】?
因为执行器要做到:
- 统一管理
- 能执行任何类型任务
- 返回值类型跟随任务自动变化
- 一个执行器万能通用
泛型方法 = 为执行器模式量身定做
泛型接口做不到!
六、最终总结
1. <T> T execute(...)
泛型方法
一个执行器 → 支持所有类型任务
每次调用方法时,T 自动变化
2. TaskExecutor<T>
泛型接口
一个执行器 → 只能支持一种固定类型
创建类时 T 就固定死
3. 业务场景
执行器必须用泛型方法,绝对不要用泛型接口!
七、泛型方法 vs 泛型接口 核心区别
java
// 1. 泛型方法(推荐执行器使用)
public interface TaskExecutor {
<T> T execute(Task<T> task);
}
- 接口无泛型,方法自带泛型
- 一个执行器可执行任意返回值类型任务
- 类型由方法调用时动态确定
- 适合任务执行器、通用处理器等场景
java
// 2. 泛型接口(不适合执行器)
public interface TaskExecutor<T> {
T execute(Task<T> task);
}
- 接口定义泛型,整个类共用一个 T
- 一个执行器只能处理固定类型任务
- 灵活性差,无法统一管理