你有没有在写 Java 的时候看到一堆泛型参数:<T>、<E>、<K, V>、<?>,然后心想,“这都什么鬼?哪个是哪个?”别慌,这其实没你想的那么抽象。今天我们就用最朴实的方式,把这些泛型的含义和用法都理一遍,代码都是真实可跑的例子,看完你就彻底不怕它了。
一、泛型到底是干嘛的?
泛型,说白了就是一种“模板”。 比如你想写一个存放对象的容器类,既能放 String,也能放 Integer,还得能放自定义对象,那不用泛型的话,你可能会写成这样:
public class Box { private Object value; public void set(Object value) { this.value = value; } public Object get() { return value; }}
表面上看挺通用,但取出来你得强转:
Box box = new Box();box.set("hello");String s = (String) box.get(); // 不强转还不行
一旦你强转错类型,比如拿个 Integer 强转成 String,直接 ClassCastException。
这就不优雅了,泛型就是为了解决这种问题的。 换成泛型版:
public class Box<T> { private T value; public void set(T value) { this.value = value; } public T get() { return value; }}
这样你创建时就指定类型:
Box<String> box = new Box<>();box.set("hello");String s = box.get(); // 再也不用强转
是不是清爽多了?
二、T、E、K、V 都是什么鬼?
其实这些字母没啥神秘的含义,它们只是“约定俗成”的写法。 你要非写 <A>、<X> 也行,就是别人看你代码可能懵。
一般用法是这样的:
| 字母 | 含义 | 常见场景 |
|---|---|---|
| T | Type(类型) | 单个通用类型,如 List<T> |
| E | Element(元素) | 集合中的元素类型,如 List<E> |
| K | Key(键) | 键值对中的键,如 Map<K,V> |
| V | Value(值) | 键值对中的值,如 Map<K,V> |
| ? | 通配符(unknown type) | 表示未知类型,比如方法参数中不关心具体类型 |
举个例子你就懂了:
Map<Integer, String> map = new HashMap<>();map.put(1, "Java");map.put(2, "泛型");
这里 K 就是 Integer,V 就是 String。 所以泛型的意思其实很直白,就是定义一个“类型变量”,用的时候再指定。
三、T 和 ? 的区别(这是面试常考点)
很多人一看到 ? 就蒙了,明明也是“泛型”,为啥不写 T 呢? 其实它俩的区别是这样的:
T是在定义类或方法时声明的类型变量。?是在使用泛型时,表示未知类型。
比如你定义一个方法:
public <T> void printList(List<T> list) { for (T item : list) { System.out.println(item); }}
这里 <T> 是声明,这个方法可以接受任何类型的 List。 但是下面这个:
public void printList2(List<?> list) { for (Object item : list) { System.out.println(item); }}
这里用的是 ?,意思是“我不在乎它是什么类型,只要是个 List 就行”。
区别就在于:<T> 让你在方法中还可以知道类型,<?> 则完全放弃了类型信息。
四、上界通配符和下界通配符
你可能还见过这种奇怪的写法:
List<? extends Number>List<? super Integer>
别急,我们慢慢拆。
1. ? extends T:上界通配符(表示“是 T 或其子类”)
比如:
public void printNumbers(List<? extends Number> list) { for (Number n : list) { System.out.println(n); }}
这个方法能接受 List<Integer>、List<Double> 等,只要元素是 Number 的子类都行。 但注意,你不能往里面加元素,因为编译器不知道你传进来的是 Integer 还是 Double。
2. ? super T:下界通配符(表示“是 T 或其父类”)
比如:
public void addIntegers(List<? super Integer> list) { list.add(1); // OK // list.add(1.5); // 编译错误}
这个方法能接受 List<Integer>、List<Number>、List<Object>。 因为 Integer 是它们的子类。 它适用于“往容器里放”的场景。
一句口诀记住:
“extends 读、super 写”——用
extends时只读不写,用super时只写不读。
五、泛型方法的定义和使用
泛型不仅能加在类上,也能加在方法上:
public class GenericMethodExample { public static <T> void print(T value) { System.out.println(value); } public static void main(String[] args) { print(123); // 自动推断为 Integer print("Hello"); // 自动推断为 String print(3.14); // 自动推断为 Double }}
是不是很灵活? 方法级的泛型特别适合工具类,比如排序、拷贝、比较等。
六、泛型擦除(Java 编译期的“小秘密”)
其实 Java 的泛型只是编译期语法糖,在运行时会被“擦除”。 比如 List<String> 和 List<Integer> 到运行时其实是一样的类型:
List<String> list1 = new ArrayList<>();List<Integer> list2 = new ArrayList<>();System.out.println(list1.getClass() == list2.getClass()); // true
输出:true。
这就是“类型擦除”。所以泛型信息在运行时是拿不到的,像下面这样会报错:
if (list1 instanceof List<String>) { } // 编译错误
一个完整的例子
来个综合的小例子,把上面的点都串起来:
class Pair<K, V> { private K key; private V value; public Pair(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public V getValue() { return value; }}class Util { publicstatic <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) { return p1.getKey().equals(p2.getKey()) && p1.getValue().equals(p2.getValue()); }}publicclass TestGeneric { public static void main(String[] args) { Pair<Integer, String> p1 = new Pair<>(1, "Java"); Pair<Integer, String> p2 = new Pair<>(1, "Java"); boolean same = Util.compare(p1, p2); System.out.println(same); // true }}
这里同时用到了 <K, V> 泛型和泛型方法 <K, V>,完全类型安全,不需要任何强转。
八、最后
T就是 Type,最常见的泛型参数。E是元素(Element),集合类里常用。K、V是 Map 的键和值。?是“我不关心类型”的通配符。? extends代表上界(读),? super代表下界(写)。- 泛型信息在运行时会被擦除(类型擦除)。
掌握了这些,其实你写泛型就不会再头大。 下次再看到 <T>、<E>、<?>,可以心里默默地说一句:“行,我知道你是谁了。”
如何高效转型Al大模型领域?
作为一名在一线互联网行业奋斗多年的老兵,我深知持续学习和进步的重要性,尤其是在复杂且深入的Al大模型开发领域。为什么精准学习如此关键?
- 系统的技术路线图:帮助你从入门到精通,明确所需掌握的知识点。
- 高效有序的学习路径:避免无效学习,节省时间,提升效率。
- 完整的知识体系:建立系统的知识框架,为职业发展打下坚实基础。
AI大模型从业者的核心竞争力
- 持续学习能力:Al技术日新月异,保持学习是关键。
- 跨领域思维:Al大模型需要结合业务场景,具备跨领域思考能力的从业者更受欢迎。
- 解决问题的能力:AI大模型的应用需要解决实际问题,你的编程经验将大放异彩。
以前总有人问我说:老师能不能帮我预测预测将来的风口在哪里?
现在没什么可说了,一定是Al;我们国家已经提出来:算力即国力!
未来已来,大模型在未来必然走向人类的生活中,无论你是前端,后端还是数据分析,都可以在这个领域上来,我还是那句话,在大语言AI模型时代,只要你有想法,你就有结果!只要你愿意去学习,你就能卷动的过别人!
现在,你需要的只是一份清晰的转型计划和一群志同道合的伙伴。作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。

第一阶段(10天):初阶应用
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
- 大模型 AI 能干什么?
- 大模型是怎样获得「智能」的?
- 用好 AI 的核心心法
- 大模型应用业务架构
- 大模型应用技术架构
- 代码示例:向 GPT-3.5 灌入新知识
- 提示工程的意义和核心思想
- Prompt 典型构成
- 指令调优方法论
- 思维链和思维树
- Prompt 攻击和防范
- …
第二阶段(30天):高阶应用
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
- 为什么要做 RAG
- 搭建一个简单的 ChatPDF
- 检索的基础概念
- 什么是向量表示(Embeddings)
- 向量数据库与向量检索
- 基于向量检索的 RAG
- 搭建 RAG 系统的扩展知识
- 混合检索与 RAG-Fusion 简介
- 向量模型本地部署
- …
第三阶段(30天):模型训练
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
- 为什么要做 RAG
- 什么是模型
- 什么是模型训练
- 求解器 & 损失函数简介
- 小实验2:手写一个简单的神经网络并训练它
- 什么是训练/预训练/微调/轻量化微调
- Transformer结构简介
- 轻量化微调
- 实验数据集的构建
- …
第四阶段(20天):商业闭环
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
- 硬件选型
- 带你了解全球大模型
- 使用国产大模型服务
- 搭建 OpenAI 代理
- 热身:基于阿里云 PAI 部署 Stable Diffusion
- 在本地计算机运行大模型
- 大模型的私有化部署
- 基于 vLLM 部署大模型
- 案例:如何优雅地在阿里云私有部署开源大模型
- 部署一套开源 LLM 项目
- 内容安全
- 互联网信息服务算法备案
- …
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。
这份完整版的大模型 AI 学习资料已经上传优快云,朋友们如果需要可以微信扫描下方优快云官方认证二维码免费领取【保证100%免费】


被折叠的 条评论
为什么被折叠?



