一、一句话总结
泛型类型参数可以是:类、接口、数组,不能是:基本类型、具体值、实例
二、允许的类型
1. 类和接口
java
// ✅ 引用类型都可以
class Box<T> {} // T可以是任何引用类型
Box<String> stringBox; // 类
Box<Integer> integerBox; // 包装类
Box<List<String>> listBox; // 泛型类
Box<Comparable> compBox; // 接口
Box<Runnable> runnableBox; // 函数式接口
2. 通配符类型
java
// ? 表示未知类型
List<?> wildcardList; // 任意类型
List<? extends Number> nums; // Number或其子类
List<? super Integer> ints; // Integer或其父类
3. 泛型数组
java
// 可以声明泛型数组引用
T[] array; // ✅ 可以声明
// T[] arr = new T[10]; // ❌ 不能创建实例
4. 嵌套泛型
java
// 多层嵌套
Map<String, List<Integer>> map; // Map的value是List
List<Map.Entry<String, Integer>> entries; // List的元素是Map.Entry
Box<Pair<String, Integer>> box; // 复杂嵌套
三、不允许的类型
1. 基本类型(最重要的限制)
java
// ❌ 不能使用基本类型
Box<int> intBox; // 编译错误!
Box<double> doubleBox; // 编译错误!
Box<char> charBox; // 编译错误!
// ✅ 必须使用包装类
Box<Integer> intBox; // 正确
Box<Double> doubleBox; // 正确
Box<Character> charBox; // 正确
2. 原始类型(不建议,但允许)
java
// ⚠️ 原始类型(raw type)- 已过时
Box rawBox = new Box(); // 警告:未指定泛型类型
Box<String> stringBox = new Box(); // ✅ 应该这样
3. 具体值/实例
java
// ❌ 不能是具体值
class Box<"string"> {} // 错误
class Box<new String()> {} // 错误
class Box<10> {} // 错误
4. 静态上下文
java
class Box<T> {
// ❌ 不能有静态泛型字段
static T staticField; // 编译错误
// ❌ 静态方法不能使用类的类型参数
static T staticMethod() { // 编译错误
return null;
}
// ✅ 静态方法可以有自己独立的泛型参数
static <U> U genericMethod(U param) {
return param;
}
}
四、边界限制
1. 类型边界
java
// 只能扩展类或实现接口,不能是其他
class Box<T extends Number & Comparable<T>> { // ✅ 正确
// T必须是Number的子类且实现Comparable
}
// ❌ 错误边界
class Box<T super String> {} // 不能使用super
class Box<T extends 100> {} // 不能是具体值
2. 多重边界
java
// 最多一个类,多个接口
class Container<T extends Number & Comparable<T> & Serializable> {
// T必须:继承Number,实现Comparable和Serializable
// 注意:类必须在前,接口在后
}
五、实际使用中的类型
1. 集合框架(最常用)
java
List<String> strings = new ArrayList<>(); // 列表
Set<Integer> numbers = new HashSet<>(); // 集合
Map<String, Integer> scores = new HashMap<>(); // 映射
Queue<Double> queue = new LinkedList<>(); // 队列
2. 自定义数据结构
java
// 节点类
class Node<T> {
T data;
Node<T> next;
Node(T data) {
this.data = data;
}
}
// 二叉树
class TreeNode<T extends Comparable<T>> {
T value;
TreeNode<T> left;
TreeNode<T> right;
}
3. 函数式接口
java
// 带泛型的函数式接口
@FunctionalInterface
interface Transformer<T, R> {
R transform(T input);
}
// 使用
Transformer<String, Integer> lengthGetter = String::length;
Transformer<Integer, String> stringConverter = Object::toString;
六、类型推断(钻石运算符)
1. 自动类型推断
java
// Java 7+ 钻石运算符
List<String> list = new ArrayList<>(); // ✅ 自动推断为<String>
// Java 7之前
List<String> list = new ArrayList<String>(); // ✅ 老写法
// 嵌套泛型也能推断
Map<String, List<Integer>> map = new HashMap<>();
2. 方法类型推断
java
// 方法调用时自动推断
<T> T getDefault(Class<T> clazz) { ... }
String str = getDefault(String.class); // T推断为String
Integer num = getDefault(Integer.class); // T推断为Integer
七、特殊限制及解决方案
1. 基本类型的解决方案
java
// 问题:不能直接用int
// Box<int> box; // ❌ 错误
// 解决方案1:使用包装类
Box<Integer> intBox = new Box<>();
// 解决方案2:使用特化版本(第三方库如fastutil)
// IntBox, LongBox等专用容器
// 解决方案3:Java未来可能支持(Valhalla项目)
2. 类型擦除的影响
java
// 运行时类型信息丢失
Box<String> stringBox = new Box<>();
Box<Integer> integerBox = new Box<>();
// 运行时都是Box<Object>
System.out.println(stringBox.getClass() == integerBox.getClass()); // true
// 解决方案:传递Class对象
class Box<T> {
private Class<T> type; // 保存类型信息
Box(Class<T> type) {
this.type = type;
}
}
八、检查清单
✅ 可以用作泛型参数:
- 任何引用类型(类、接口)
- 其他泛型类型(
List<String>) - 通配符(
?,? extends T,? super T) - 数组类型(作为声明)
❌ 不能用作泛型参数:
- 基本类型(int, double, char等)
- 具体值或实例
- 原始类型(应避免)
- 在静态上下文中使用类的类型参数
⚠️ 需要注意:
- 多重边界时类在前,接口在后
- 类型擦除导致运行时类型信息丢失
- 不能创建泛型数组实例
九、一句话记忆规则
泛型类型参数 = 任何引用类型 + 通配符,但不能是基本类型或具体值,静态上下文有限制。