Java泛型:T、E、K、V、? 全面解析
·
Java泛型:T、E、K、V、? 全面解析
一、泛型基础概念
1.1 什么是泛型?
// 没有泛型的时代 - 需要强制类型转换,容易出错
List list = new ArrayList();
list.add("hello");
String str = (String) list.get(0); // 需要强制转换
// 使用泛型 - 编译时类型安全
List<String> list = new ArrayList<>();
list.add("hello");
String str = list.get(0); // 自动类型推断,不需要转换
1.2 为什么需要泛型?
- 类型安全:编译时检查类型错误
- 消除强制类型转换:代码更简洁
- 提高代码复用性:一套代码适用于多种类型
- 更好的可读性:代码意图更明确
二、泛型类型参数详解
2.1 常用类型参数含义
| 类型参数 | 含义 | 使用场景 |
|---|---|---|
| T | Type(类型) | 表示通用的Java类型 |
| E | Element(元素) | 主要用于集合框架 |
| K | Key(键) | 主要用于Map的键 |
| V | Value(值) | 主要用于Map的值 |
| N | Number(数字) | 表示数字类型 |
| R | Result/Return(返回值) | 表示方法返回值类型 |
2.2 T (Type) - 最通用的类型参数
// 自定义泛型类
public class Box<T> {
private T content;
public Box(T content) {
this.content = content;
}
public T getContent() {
return content;
}
public void setContent(T content) {
this.content = content;
}
}
// 使用示例
Box<String> stringBox = new Box<>("Hello");
Box<Integer> intBox = new Box<>(100);
// 泛型方法
public <T> T getFirstElement(List<T> list) {
if (list == null || list.isEmpty()) {
return null;
}
return list.get(0);
}
// 多个类型参数
public class Pair<T, U> {
private T first;
private U second;
public Pair(T first, U second) {
this.first = first;
this.second = second;
}
// getters and setters
}
2.3 E (Element) - 集合元素的类型
// 集合接口中的使用
public interface List<E> {
boolean add(E e);
E get(int index);
// ...
}
// 自定义集合类
public class MyStack<E> {
private List<E> elements = new ArrayList<>();
public void push(E element) {
elements.add(element);
}
public E pop() {
if (elements.isEmpty()) {
throw new EmptyStackException();
}
return elements.remove(elements.size() - 1);
}
}
// 使用示例
MyStack<String> stack = new MyStack<>();
stack.push("Java");
stack.push("Generic");
String top = stack.pop(); // 返回"Generic"
2.4 K, V (Key, Value) - Map键值对的类型
// Map接口定义
public interface Map<K, V> {
V put(K key, V value);
V get(Object key);
// ...
}
// 自定义缓存类
public class LRUCache<K, V> {
private final LinkedHashMap<K, V> cache;
private final int capacity;
public LRUCache(int capacity) {
this.capacity = capacity;
this.cache = new LinkedHashMap<K, V>(capacity, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > capacity;
}
};
}
public V get(K key) {
return cache.get(key);
}
public void put(K key, V value) {
cache.put(key, value);
}
}
// 使用示例
LRUCache<String, User> userCache = new LRUCache<>(100);
userCache.put("user1", new User("Alice"));
User user = userCache.get("user1");
2.5 N (Number) - 数字类型的泛型
// 数字计算工具类
public class Calculator<N extends Number> {
public double sum(List<N> numbers) {
return numbers.stream()
.mapToDouble(Number::doubleValue)
.sum();
}
// 泛型边界:必须是Number或其子类
public <N extends Number & Comparable<N>> N max(N a, N b) {
return a.compareTo(b) > 0 ? a : b;
}
}
// 使用示例
Calculator<Integer> intCalc = new Calculator<>();
List<Integer> ints = Arrays.asList(1, 2, 3, 4, 5);
double intSum = intCalc.sum(ints); // 15.0
Calculator<Double> doubleCalc = new Calculator<>();
List<Double> doubles = Arrays.asList(1.1, 2.2, 3.3);
double doubleSum = doubleCalc.sum(doubles); // 6.6
2.6 R (Return) - 返回值的泛型
// 函数式接口中的使用
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
// ...
}
// 通用响应对象
public class ApiResponse<R> {
private boolean success;
private String message;
private R data;
private int code;
// 静态工厂方法
public static <R> ApiResponse<R> success(R data) {
ApiResponse<R> response = new ApiResponse<>();
response.setSuccess(true);
response.setData(data);
response.setCode(200);
return response;
}
public static <R> ApiResponse<R> error(String message, int code) {
ApiResponse<R> response = new ApiResponse<>();
response.setSuccess(false);
response.setMessage(message);
response.setCode(code);
return response;
}
// getters and setters
}
// 使用示例
ApiResponse<User> userResponse = ApiResponse.success(new User("Alice"));
ApiResponse<List<Product>> productResponse = ApiResponse.success(productList);
三、通配符 ? 的深入理解
3.1 无界通配符 (?)
// 可以接受任何类型的List
public void printList(List<?> list) {
for (Object elem : list) {
System.out.println(elem);
}
}
// 使用示例
List<String> strings = Arrays.asList("a", "b", "c");
List<Integer> integers = Arrays.asList(1, 2, 3);
printList(strings); // 可以
printList(integers); // 可以
// 但只能读,不能写(除了null)
list.add("test"); // 编译错误!
list.add(null); // 可以
3.2 上界通配符 (? extends T)
// 只能读取,不能添加(除了null)
public double sumOfList(List<? extends Number> list) {
double sum = 0.0;
for (Number num : list) {
sum += num.doubleValue();
}
return sum;
}
// 使用示例
List<Integer> ints = Arrays.asList(1, 2, 3);
List<Double> doubles = Arrays.asList(1.1, 2.2, 3.3);
double intSum = sumOfList(ints); // 6.0
double doubleSum = sumOfList(doubles); // 6.6
// 编译错误:不能添加元素(除了null)
list.add(new Integer(10)); // 错误!
list.add(null); // 正确
3.3 下界通配符 (? super T)
// 可以添加T及其子类,读取为Object
public void addNumbers(List<? super Integer> list) {
for (int i = 1; i <= 10; i++) {
list.add(i); // 可以添加Integer
list.add(Integer.valueOf(i)); // 也可以
}
}
// 使用示例
List<Number> numbers = new ArrayList<>();
List<Object> objects = new ArrayList<>();
List<Integer> integers = new ArrayList<>();
addNumbers(numbers); // 可以 - Number是Integer的父类
addNumbers(objects); // 可以 - Object是Integer的父类
addNumbers(integers); // 编译错误!Integer不是Integer的父类
// 读取时只能作为Object
Object obj = list.get(0); // 只能作为Object读取
3.4 PECS原则(Producer-Extends, Consumer-Super)
// Producer - 提供数据(使用extends)
public class CollectionsUtil {
// 从源集合拷贝到目标集合
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
for (int i = 0; i < src.size(); i++) {
dest.set(i, src.get(i));
}
}
// 获取最大值
public static <T extends Comparable<? super T>> T max(List<? extends T> list) {
if (list.isEmpty()) throw new NoSuchElementException();
T max = list.get(0);
for (T elem : list) {
if (elem.compareTo(max) > 0) {
max = elem;
}
}
return max;
}
}
// 使用示例
List<Number> dest = new ArrayList<>();
List<Integer> src = Arrays.asList(1, 2, 3);
CollectionsUtil.copy(dest, src); // dest现在包含[1, 2, 3]
四、实际应用场景
4.1 DAO层通用接口
// 通用DAO接口
public interface BaseDao<T, ID> {
T findById(ID id);
List<T> findAll();
T save(T entity);
void delete(ID id);
boolean existsById(ID id);
}
// 实现
public abstract class AbstractJpaDao<T, ID> implements BaseDao<T, ID> {
private final Class<T> entityClass;
@PersistenceContext
protected EntityManager entityManager;
protected AbstractJpaDao(Class<T> entityClass) {
this.entityClass = entityClass;
}
@Override
public T findById(ID id) {
return entityManager.find(entityClass, id);
}
@Override
public List<T> findAll() {
CriteriaQuery<T> query = entityManager.getCriteriaBuilder()
.createQuery(entityClass);
query.select(query.from(entityClass));
return entityManager.createQuery(query).getResultList();
}
// 其他方法实现...
}
// 具体DAO
@Repository
public class UserDao extends AbstractJpaDao<User, Long> {
public UserDao() {
super(User.class);
}
// 特定方法
public Optional<User> findByUsername(String username) {
// 实现...
}
}
4.2 服务层通用封装
// 通用服务接口
public interface BaseService<T, ID, DTO> {
DTO findById(ID id);
List<DTO> findAll();
DTO create(DTO dto);
DTO update(ID id, DTO dto);
void delete(ID id);
}
// 通用服务实现
public abstract class AbstractService<T, ID, DTO>
implements BaseService<T, ID, DTO> {
protected final BaseDao<T, ID> dao;
protected final Converter<T, DTO> converter;
public AbstractService(BaseDao<T, ID> dao, Converter<T, DTO> converter) {
this.dao = dao;
this.converter = converter;
}
@Override
public DTO findById(ID id) {
T entity = dao.findById(id);
if (entity == null) {
throw new ResourceNotFoundException("Resource not found with id: " + id);
}
return converter.toDto(entity);
}
@Override
public List<DTO> findAll() {
return dao.findAll().stream()
.map(converter::toDto)
.collect(Collectors.toList());
}
// 其他方法实现...
}
// 转换器接口
public interface Converter<ENTITY, DTO> {
DTO toDto(ENTITY entity);
ENTITY toEntity(DTO dto);
void updateEntity(DTO dto, ENTITY entity);
}
4.3 构建器模式中的泛型
// 通用构建器
public class GenericBuilder<T> {
private final Supplier<T> supplier;
private List<Consumer<T>> modifiers = new ArrayList<>();
public GenericBuilder(Supplier<T> supplier) {
this.supplier = supplier;
}
public static <T> GenericBuilder<T> of(Supplier<T> supplier) {
return new GenericBuilder<>(supplier);
}
public <U> GenericBuilder<T> with(BiConsumer<T, U> consumer, U value) {
modifiers.add(instance -> consumer.accept(instance, value));
return this;
}
public T build() {
T instance = supplier.get();
modifiers.forEach(modifier -> modifier.accept(instance));
modifiers.clear();
return instance;
}
}
// 使用示例
User user = GenericBuilder.of(User::new)
.with(User::setId, 1L)
.with(User::setUsername, "alice")
.with(User::setEmail, "alice@example.com")
.build();
五、高级特性
5.1 类型擦除与补偿
// 类型擦除示例
public class ErasureExample<T> {
private T value;
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
// 编译后变成:
// private Object value;
// public void setValue(Object value) {...}
// public Object getValue() {...}
}
// 获取泛型实际类型
public abstract class TypeReference<T> {
private final Type type;
protected TypeReference() {
Type superClass = getClass().getGenericSuperclass();
this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
}
public Type getType() {
return type;
}
}
// 使用
TypeReference<List<String>> typeRef = new TypeReference<List<String>>() {};
Type type = typeRef.getType(); // 获取List<String>的实际类型
5.2 泛型与反射
public class GenericReflectionUtil {
// 获取泛型类的实际类型参数
public static Type[] getGenericTypes(Class<?> clazz) {
Type genericSuperclass = clazz.getGenericSuperclass();
if (genericSuperclass instanceof ParameterizedType) {
return ((ParameterizedType) genericSuperclass).getActualTypeArguments();
}
return new Type[0];
}
// 创建泛型实例
@SuppressWarnings("unchecked")
public static <T> T createGenericInstance(Class<T> rawType, Type... typeArgs) {
try {
// 使用Gson或Jackson等库可以更好地处理
return rawType.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException("Failed to create instance", e);
}
}
}
六、常见陷阱与最佳实践
6.1 常见陷阱
// 1. 不能创建泛型数组
// T[] array = new T[10]; // 编译错误
// 正确方式
public class GenericArray<T> {
private T[] array;
@SuppressWarnings("unchecked")
public GenericArray(Class<T> type, int size) {
array = (T[]) Array.newInstance(type, size); // 使用反射创建
}
}
// 2. instanceof 不能用于泛型
public <T> void checkType(Object obj) {
// if (obj instanceof T) { } // 编译错误
// 正确方式
if (obj instanceof String) { } // 具体类型可以
}
// 3. 静态成员不能使用泛型类型参数
public class StaticGeneric<T> {
// private static T staticField; // 编译错误
// 但可以使用泛型方法
public static <U> U staticMethod(U param) {
return param;
}
}
6.2 最佳实践
-
命名规范:
- 使用单个大写字母:T、E、K、V等
- 具有描述性:如T表示类型,E表示元素
-
尽量使用泛型方法:
// 优于类级别的泛型
public class CollectionUtils {
public static <T> List<T> filter(List<T> list, Predicate<T> predicate) {
return list.stream()
.filter(predicate)
.collect(Collectors.toList());
}
}
- 合理使用边界:
// 需要比较时
public static <T extends Comparable<? super T>> void sort(List<T> list)
// 需要序列化时
public static <T extends Serializable> T deepCopy(T obj)
- 文档化泛型约束:
/**
* 处理订单的服务
*
* @param <T> 订单类型
* @param <R> 返回结果类型
* @param <P> 支付信息类型
*/
public interface OrderService<T extends Order, R extends Result, P extends Payment> {
R processOrder(T order, P payment);
}
七、总结对比
| 概念 | 含义 | 使用场景 | 示例 |
|---|---|---|---|
| T (Type) | 通用类型 | 类、接口、方法的通用类型 | Box<T>, List<T> |
| E (Element) | 集合元素 | 集合框架 | List<E>, Set<E> |
| K (Key) | Map键 | Map接口及相关类 | Map<K, V>, HashMap<K, V> |
| V (Value) | Map值 | Map接口及相关类 | Map<K, V>, HashMap<K, V> |
| ? (通配符) | 未知类型 | 方法参数,限制读写 | List<?>, List<? extends Number> |
| ? extends T | 上界通配符 | 生产者,只读 | List<? extends Number> |
| ? super T | 下界通配符 | 消费者,可写 | List<? super Integer> |
记住关键点:
- T、E、K、V本质相同:都是类型参数,只是命名约定不同
- 通配符?表示未知类型:提供更大的灵活性
- PECS原则:Producer使用extends,Consumer使用super
- 类型擦除:泛型在运行时被擦除,编译时检查
掌握了这些概念和用法,你就可以在Java开发中更加自如地使用泛型,写出更安全、更灵活、更可复用的代码!
更多推荐




所有评论(0)