泛型机制
外观
泛型机制[编辑 | 编辑源代码]
泛型(Generics)是Java编程语言中一项强大的特性,它允许开发者在编译时检测类型错误,提高代码的安全性和可重用性。泛型通过参数化类型(type parameters)来实现,使得类、接口和方法可以操作多种数据类型而不必牺牲类型安全性。
介绍[编辑 | 编辑源代码]
泛型的主要目的是在编译时提供更强的类型检查,并消除类型转换的需要。在Java 5之前,集合类(如ArrayList)只能存储Object类型,这意味着每次从集合中取出元素时都需要进行强制类型转换,容易引发运行时错误。泛型的引入解决了这一问题。
泛型的核心概念包括:
- 类型参数:在类、接口或方法声明中使用的占位符,例如`<T>`。
- 类型擦除:Java泛型在运行时会被擦除,转换为原始类型(raw types)。
- 通配符:`?`用于表示未知类型,通常与`extends`和`super`结合使用。
基本语法[编辑 | 编辑源代码]
泛型类[编辑 | 编辑源代码]
泛型类在类名后使用尖括号声明类型参数。例如:
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, Generics!");
String value = stringBox.getContent(); // 无需强制类型转换
System.out.println(value); // 输出: Hello, Generics!
泛型方法[编辑 | 编辑源代码]
泛型方法在返回类型前声明类型参数:
public <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
使用示例:
Integer[] intArray = {1, 2, 3};
printArray(intArray); // 输出: 1 2 3
类型擦除[编辑 | 编辑源代码]
Java的泛型是通过类型擦除实现的,这意味着泛型类型信息在运行时不可用。例如,`Box<String>`和`Box<Integer>`在运行时都会被擦除为`Box`。
擦除后的代码示例[编辑 | 编辑源代码]
编译前:
Box<String> box = new Box<>();
box.setContent("Test");
String content = box.getContent();
编译后(等效代码):
Box box = new Box();
box.setContent("Test");
String content = (String) box.getContent();
通配符[编辑 | 编辑源代码]
通配符`?`用于表示未知类型,通常用于方法参数或变量声明。
上限通配符(extends)[编辑 | 编辑源代码]
限制类型为某个类的子类:
public void process(List<? extends Number> numbers) {
for (Number num : numbers) {
System.out.println(num);
}
}
下限通配符(super)[编辑 | 编辑源代码]
限制类型为某个类的父类:
public void addNumbers(List<? super Integer> list) {
list.add(1);
list.add(2);
}
实际应用案例[编辑 | 编辑源代码]
集合框架中的泛型[编辑 | 编辑源代码]
Java集合框架广泛使用泛型来保证类型安全:
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
// names.add(123); // 编译错误,类型不匹配
自定义比较器[编辑 | 编辑源代码]
泛型可用于创建可重用的比较逻辑:
public class Comparator<T extends Comparable<T>> {
public T max(T a, T b) {
return a.compareTo(b) > 0 ? a : b;
}
}
高级主题[编辑 | 编辑源代码]
类型边界[编辑 | 编辑源代码]
可以使用`extends`限制类型参数的范围:
public class Calculator<T extends Number> {
public double add(T a, T b) {
return a.doubleValue() + b.doubleValue();
}
}
泛型与继承[编辑 | 编辑源代码]
泛型类可以继承或实现其他泛型类/接口:
public interface Repository<T> {
void save(T entity);
}
public class UserRepository implements Repository<User> {
@Override
public void save(User user) {
// 实现保存逻辑
}
}
常见问题[编辑 | 编辑源代码]
为什么不能创建泛型数组?[编辑 | 编辑源代码]
由于类型擦除,Java不允许创建泛型数组。例如:
// 以下代码会导致编译错误
List<String>[] arrayOfLists = new List<String>[10];
泛型与原始类型的区别[编辑 | 编辑源代码]
原始类型(raw types)是不带类型参数的泛型类,为了向后兼容而保留,但不推荐使用:
List rawList = new ArrayList(); // 原始类型
rawList.add("String");
rawList.add(1); // 编译通过,但可能引发运行时错误
总结[编辑 | 编辑源代码]
泛型是Java中提高代码安全性和可重用性的重要特性。通过类型参数化,开发者可以:
- 在编译时捕获类型错误
- 消除强制类型转换
- 编写更通用的代码
虽然类型擦除带来了一些限制,但合理使用泛型能显著提高代码质量。对于初学者,建议从简单的泛型类和泛型方法开始练习,逐步掌握更高级的用法如通配符和类型边界。