在Java中,有两种使用泛型的方式:
代码示例:
抽象类
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import java.util.Objects;
@Slf4j
public abstract class EventHandle<T> {
private final Class<T> clazz;
protected EventHandle(Class<T> clazz) {
this.clazz = clazz;
}
public void excecute(String eventData) {
T model = JSON.parseObject(eventData, clazz);
if (Objects.isNull(model)) {
log.info("eventData is null");
return;
}
handle(model);
}
protected abstract void handle(T obj);
}
实现类
@Slf4j
public class EquipOtaProgressEventHandle extends EventHandle<DeviceOtaProgressModel> {
@Autowired
private RedisCacheService redisCacheService;
@Autowired
private MessageService messageService;
public EquipOtaProgressEventHandle() {
super(DeviceOtaProgressModel.class);
}
/**
*
*
* @param model
*/
@Override
protected void handle(DeviceOtaProgressModel model) {
log.info("deviceOtaProgressResultModel={}", JSON.toJSONString(model));
//数据构造
EquipmentOtaProgressVO vo = buildVo(model);
// 业务逻辑
}
}
场景,在一个类中给某一个方法定义了泛型的使用。这个泛型定义只针对该方法,也只作用于这个方法。
public class KafkaMsgSender {
public void postDeviceOnline(String name, DeviceEnum DeviceEnum) {
// 业务逻辑。。。
}
public <T> void postCoreEvent(String name, T params, String method) {
BaseRequestModel<T> baseRequestModel = new BaseRequestModel<>(params, method);
String message = JSON.toJSONString(baseRequestModel);
}
}
void前面加 <T>?<T>是泛型方法的「类型参数声明」,它告诉编译器:这是一个泛型方法,T是一个类型占位符,而不是一个具体的类名。
public <T> void postCoreEvent(String name, T params, String method) {
BaseRequestModel<T> baseRequestModel = new BaseRequestModel<>(params, method);
String message = JSON.toJSONString(baseRequestModel);
}
各部分含义
| 部分 | 作用 |
|---|---|
<T> | 声明类型参数(必须) |
void | 方法返回值 |
T params | 使用类型参数 T |
<T>?1. 错误写法(编译失败)
// ❌ 编译错误:找不到符号 T
public void postCoreEvent(String name, T params, String method) {
// 编译器会认为 T 是一个具体的类
// 如果项目中没有 T.java,直接报错
}
原因:
没有 <T>,编译器会把 T当作一个具体的类名,而不是泛型。
写法一:泛型方法(推荐)
public <T> void postCoreEvent(String name, T params, String method) {
// T 是泛型参数
}
写法二:类级别泛型
public class EventPublisher<T> {
// 不需要在方法上再写 <T>
public void postCoreEvent(String name, T params, String method) {
// T 来自类定义
}
}
1. 泛型方法(独立泛型)
public class EventUtil {
// 方法级别的泛型:每次调用可以传入不同类型
public <T> void postCoreEvent(String name, T params, String method) {
System.out.println(params.getClass()); // 运行时类型
}
}
// 调用
eventUtil.postCoreEvent("event1", new User(), "create"); // T = User
eventUtil.postCoreEvent("event2", "hello", "notify"); // T = String
2. 类级别泛型(固定类型)
public class EventPublisher<T> {
// 类级别的泛型:整个类使用同一种类型
public void postCoreEvent(String name, T params, String method) {
System.out.println(params.getClass());
}
}
// 使用
EventPublisher<User> publisher = new EventPublisher<>();
publisher.postCoreEvent("event1", new User(), "create"); // T 固定为 User
// publisher.postCoreEvent("event2", "hello", "notify"); // ❌ 编译错误:需要 User 类型
<T>?BaseRequestModel<T> baseRequestModel = new BaseRequestModel<>(params, method);
这里:
BaseRequestModel<T>是一个泛型类T必须来自方法声明 <T>误解 1:参数里的 T已经声明了泛型
// 错误理解
public void postCoreEvent(String name, T params, String method)
// 这里的 T 不是声明,而是使用
真相:
<T>(在返回类型前)T params(在参数中)误解 2:泛型只在参数里用,不需要声明
// 编译错误
public void postCoreEvent(String name, List<T> params) {
// List<T> 中的 T 也需要先声明
}
正确写法:
public <T> void postCoreEvent(String name, List<T> params) {
// 先声明 <T>,才能使用 List<T>
}
1. 泛型方法的正确使用
public class EventService {
// 泛型方法
public <T> void postCoreEvent(String name, T params, String method) {
BaseRequestModel<T> request = new BaseRequestModel<>(params, method);
System.out.println("Event: " + name);
System.out.println("Method: " + method);
System.out.println("Params: " + params);
}
// 多泛型参数
public <T, R> R convert(T source, Function<T, R> converter) {
return converter.apply(source);
}
}
2. 调用示例
EventService service = new EventService();
// T = String
service.postCoreEvent("USER_LOGIN", "user123", "login");
// T = UserDTO
UserDTO user = new UserDTO("张三", 18);
service.postCoreEvent("USER_CREATE", user, "create");
// T = Integer, R = String
String result = service.convert(123, i -> "数字:" + i);
1. 方法独立泛型 → 用 <T>
public <T> void publish(T event) {
// 方法级别的泛型
}
2. 类固定泛型 → 不用 <T>
public class Publisher<T> {
public void publish(T event) {
// 类级别的泛型
}
}
3. 多个泛型参数
public <T, R> R handle(T request, Class<R> responseType) {
// T 是请求类型,R 是响应类型
}
4. 有界泛型
public <T extends BaseEvent> void publish(T event) {
// T 必须是 BaseEvent 的子类
}
| 问题 | 答案 |
|---|---|
为什么要加 <T>? | 声明这是一个泛型方法,T是类型参数 |
参数里的 T算声明吗? | 不算,那是使用 |
不加 <T>会怎样? | 编译错误:找不到符号 T |
| 什么时候可以不加? | 当类已经声明了泛型 <T>时 |
一句话总结:
<T>是泛型方法的“身份证”,没有它,编译器不知道T是类型参数还是具体类。