在Java 5之前,集合类(如ArrayList
)只能存储Object
类型,使用时需要强制类型转换,容易引发ClassCastException
。泛型的引入解决了以下问题:
示例对比:
// Java 5 之前(非泛型)
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0); // 需要强制转换
// 使用泛型
List<String> list = new ArrayList<>();
list.add("hello");
String s = list.get(0); // 自动类型推断
在类名后使用
定义类型参数:
public class Box<T> {
private T content;
public void setContent(T content) {
this.content = content;
}
public T getContent() {
return content;
}
}
// 使用示例
Box<String> stringBox = new Box<>();
stringBox.setContent("Hello");
Box<Integer> intBox = new Box<>();
intBox.setContent(100);
在方法返回类型前定义类型参数:
public <T> T getFirstElement(List<T> list) {
if (list == null || list.isEmpty()) {
return null;
}
return list.get(0);
}
// 使用示例
List<String> names = Arrays.asList("Alice", "Bob");
String first = getFirstElement(names); // 自动类型推断
public interface Repository<T> {
void save(T entity);
T findById(int id);
}
// 实现示例
public class UserRepository implements Repository<User> {
@Override
public void save(User user) { /* ... */ }
@Override
public User findById(int id) { /* ... */ }
}
用于处理未知类型的泛型集合:
语法 | 说明 | 示例 |
---|---|---|
> |
无限定通配符(未知类型) | List> |
extends T> |
上界通配符(T或其子类) | List extends Number> |
super T> |
下界通配符(T或其父类) | List super Integer> |
示例:处理不同数值类型的集合
public static double sum(List<? extends Number> numbers) {
double sum = 0.0;
for (Number num : numbers) {
sum += num.doubleValue();
}
return sum;
}
// 使用示例
List<Integer> ints = Arrays.asList(1, 2, 3);
List<Double> doubles = Arrays.asList(1.1, 2.2);
System.out.println(sum(ints)); // 输出 6.0
System.out.println(sum(doubles)); // 输出 3.3
Java泛型在编译后会进行类型擦除,转换为原始类型:
T
会被替换为Object
(或上界类型)示例:编译后的代码
// 源代码
public class Box<T> {
private T content;
public T getContent() { return content; }
}
// 编译后(类型擦除)
public class Box {
private Object content;
public Object getContent() { return content; }
}
由于类型擦除,Java不允许直接创建泛型数组:
// 编译错误!
T[] array = new T[10];
// 正确做法:使用Object数组+类型转换
T[] array = (T[]) new Object[10];
public class Cache<K, V> {
private final Map<K, V> cache = new HashMap<>();
public void put(K key, V value) {
cache.put(key, value);
}
public V get(K key) {
return cache.get(key);
}
public void remove(K key) {
cache.remove(key);
}
}
// 使用示例
Cache<String, User> userCache = new Cache<>();
userCache.put("user1", new User("Alice"));
User user = userCache.get("user1");
public class PersonBuilder<T extends PersonBuilder<T>> {
protected Person person = new Person();
public T name(String name) {
person.setName(name);
return self();
}
public T age(int age) {
person.setAge(age);
return self();
}
protected T self() {
return (T) this;
}
public Person build() {
return person;
}
}
// 子类扩展
public class EmployeeBuilder extends PersonBuilder<EmployeeBuilder> {
public EmployeeBuilder department(String department) {
((Employee) person).setDepartment(department);
return this;
}
}
// 使用示例
Employee emp = new EmployeeBuilder()
.name("Bob")
.age(30)
.department("IT")
.build();
public class GenericComparator<T> implements Comparator<T> {
private final Function<T, Comparable> keyExtractor;
public GenericComparator(Function<T, Comparable> keyExtractor) {
this.keyExtractor = keyExtractor;
}
@Override
public int compare(T a, T b) {
return keyExtractor.apply(a).compareTo(keyExtractor.apply(b));
}
}
// 使用示例
List<Person> people = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30)
);
people.sort(new GenericComparator<>(Person::getName)); // 按姓名排序
people.sort(new GenericComparator<>(Person::getAge)); // 按年龄排序
命名约定:
T
:通用类型E
:集合元素类型K
/V
:键值对中的键和值N
:数字类型避免使用原生类型:
// 不推荐
List list = new ArrayList();
// 推荐
List<String> list = new ArrayList<>();
优先使用泛型方法:
// 不推荐
class Utils {
public static void printList(List<Object> list) { ... }
}
// 推荐
public static <T> void printList(List<T> list) { ... }
谨慎使用通配符:
List>
:只读操作(不能添加元素)List extends T>
:生产者(只能读取)List super T>
:消费者(可以写入)// 可以!静态方法需要单独声明类型参数
public static <T> T getFirst(List<T> list) { ... }
由于类型擦除,运行时无法直接获取泛型类型:
// 错误方式!
if (obj instanceof List<String>) { ... }
// 正确方式:检查原始类型
if (obj instanceof List) { ... }
可以通过ParameterizedType
获取泛型信息:
Type type = myList.getClass().getGenericSuperclass();
if (type instanceof ParameterizedType) {
Type[] typeArgs = ((ParameterizedType) type).getActualTypeArguments();
Class<?> clazz = (Class<?>) typeArgs[0];
System.out.println("泛型类型: " + clazz.getName());
}
Java泛型是提升代码安全性和可重用性的强大工具。关键要点:
>
, extends T>
, super T>
)提供灵活的API设计进一步学习:
你在使用泛型时遇到过哪些问题?欢迎在评论区讨论!