Java 泛型支持的类型

一、一句话总结

泛型类型参数可以是:类、接口、数组,不能是:基本类型、具体值、实例

二、允许的类型

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;
    }
}

八、检查清单

✅ 可以用作泛型参数:

  1. 任何引用类型(类、接口)
  2. 其他泛型类型(List<String>)
  3. 通配符(?, ? extends T, ? super T)
  4. 数组类型(作为声明)

❌ 不能用作泛型参数:

  1. 基本类型(int, double, char等)
  2. 具体值或实例
  3. 原始类型(应避免)
  4. 在静态上下文中使用类的类型参数

⚠️ 需要注意:

  1. 多重边界时类在前,接口在后
  2. 类型擦除导致运行时类型信息丢失
  3. 不能创建泛型数组实例

九、一句话记忆规则

泛型类型参数 = 任何引用类型 + 通配符,但不能是基本类型或具体值,静态上下文有限制。

相关推荐
lazy H3 分钟前
【计算机网络】第 15 篇:Java BIO、NIO 与高并发网络通信——从 Socket 理解 I/O 模型
网络·后端·tcp/ip·计算机网络·nio·408
geovindu13 分钟前
rust: Semaphore Pattern
开发语言·后端·设计模式·rust·代理模式·企业级信号量模式·同步型模式
Thneonl2 小时前
Claude Code 频繁 Compacting?发布次日我根治了 2 个痛点
后端·rust
环境栈笔记3 小时前
指纹浏览器安卓怎么用?从运行位置到功能验收,先把三种方案分清
前端·人工智能·后端·自动化
小小张说故事4 小时前
Python 的 list 为什么能装下任何类型?拆开 PyObject* 数组,以及它让你多付了多少内存
后端·python
小蒜学长4 小时前
基于SpringBoot 框架的自媒体新闻系统的设计与实现(代码+数据库+LW)
java·spring boot·后端·mysql数据库·自媒体新闻管理系统
IT_陈寒5 小时前
JavaScript实战技巧总结:深挖数组遍历的性能陷阱与实战解法
前端·人工智能·后端
学长毕设14 小时前
基于springboot的食品仓库管理系统
java·spring boot·后端
滴滴答答哒15 小时前
ASP.NET Core + FaceRecognitionDotNet 人脸识别实战:DI 单例、特征向量持久化与 1:N 比对
后端·asp.net
captain37617 小时前
MyBatis操作数据库(入门2)
java·数据库·spring boot·后端·spring·mybatis