Java之泛型

Java之泛型

目录

泛型类

语法

使用

泛型上界

定义

使用

类型擦除

通配符

通配符上界

 通配符下界

泛型方法

语法

使用 

泛型的限制


泛型类
语法
class 泛型类名称<类型形参列表> {
        // 这里可以使用类型参数
}


class ClassName<T1, T2, ..., Tn> {
}



class 泛型类名称<类型形参列表> extends 继承类/* 这里可以使用类型参数 */ {
        // 这里可以使用类型参数
}


class ClassName<T1, T2, ..., Tn> extends ParentClass<T1> {
        // 可以只使用部分类型参数
}
使用
泛型类<类型实参> 变量名; // 定义一个泛型类引用
new 泛型类<类型实参>(构造方法实参); // 实例化一个泛型类对象 
class MyArray<T> { public Object[] array = new Object[10]; public void set(int pos,T val) { array[pos] = val; } public T get(int pos) { return (T)array[pos]; } public Object[] getArray() { return array; } } public class Test { public static void main(String[] args) { MyArray<String> myArray = new MyArray<>(); } }
泛型上界

在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束。

定义
class 泛型类名称<类型形参 extends 类型边界> {
        ...
使用
class MyArray<T extends Number> { public Object[] array = new Object[10]; public void set(int pos,T val) { array[pos] = val; } public T get(int pos) { return (T)array[pos]; } public Object[] getArray() { return array; } } public class Test { public static void main(String[] args) { // 编译错误,因为 String 不是 Number 的子类型 // MyArray<String> myArray1 = new MyArray<>(); // 正常,因为 Integer 是 Number 的子类型 MyArray<Integer> myArray = new MyArray<>(); } }
class Alg<T extends Comparable<T>> { public T findMax(T[] array) { T max = array[0]; for (int i = 1; i < array.length; i++) { if(array[i].compareTo(max) > 0) { max = array[i]; } } return max; } }

类型擦除

Java中的泛型擦除是Java泛型实现的一个关键特性,它允许Java在编译时检查类型安全,但在运行时忽略泛型信息。这意味着,尽管你可以在编译时指定泛型类型,但在运行时,JVM看到的只是原始类型,并不保留任何关于泛型参数的信息。

class MyArray<E> { // E 会被擦除为 Object } class MyArray<E extends Comparable<E>> { // E 被擦除为 Comprable }

 示例

class Alg<T extends Comparable<T>> { public T findMax(T[] array) { T max = array[0]; for (int i = 1; i < array.length; i++) { if(array[i].compareTo(max) > 0) { max = array[i]; } } return max; } }

针对上面的代码,编译结果如下:

编译器在类型擦除阶段做什么?

一、擦除泛型类型信息
移除类型参数:编译器会移除所有与泛型相关的类型参数信息。这意味着在编译后的字节码中,将不再包含任何泛型类型参数的信息。
替换为原始类型:泛型类型参数会被替换为其上界(如果指定了上界的话,比如T extends Comparable<T>中的T会被替换为Comparable<T>;如果没有指定上界,则默认为Object)。例如,List<String>和List<Integer>在编译后的字节码中都表现为List。
二、调整类型信息
方法参数、局部变量和字段的类型调整:除了泛型类型本身被擦除外,编译器还会相应地调整方法参数、局部变量和字段的类型,以确保它们在运行时的一致性。
三、插入类型转换
类型强制转换:由于类型信息在运行时不可用,编译器会在需要的地方插入必要的类型转换。例如,从List<String>中获取元素时,虽然运行时这个列表只是普通的List,但编译器会在幕后添加一个从Object到String的显式类型转换。
四、确保类型安全
编译时类型检查:在编译阶段,编译器会利用泛型类型信息进行类型检查,确保类型安全。例如,编译器会阻止向List<String>中添加整数或其他非字符串对象,或者尝试将List<Integer>赋值给List<Double>等不兼容的操作。
五、桥接方法的生成
向后兼容性:为了保持与未使用泛型的旧代码的兼容性,编译器可能会为泛型类生成桥接方法。这些桥接方法允许泛型类的方法与原生类型的方法共存,并且可以相互调用。
总的来说,编译器在类型擦除阶段的主要目标是确保泛型代码在运行时能够安全、正确地执行,同时尽量减少对现有代码的影响。通过移除泛型类型信息并插入必要的类型转换,编译器使得泛型代码能够与非泛型代码无缝对接,从而保证了Java平台的整体一致性和稳定性。 
通配符
?用于在泛型的使用,即为通配符。
class Message<T> { private T message; public T getMessage() { return message; } public void setMessage(T message) { this.message = message; } } public class Test{ //可以传入任意类型的Message public static void fun(Message<?> temp){ System.out.println(temp.getMessage()); } public static void main(String[] args) { Message<String> message = new Message<>(); message.setMessage("你好!"); fun(message); Message<Integer> message2 = new Message<>(); message2.setMessage(199); fun(message2); } }
通配符上界
<? extends 上界> 
上界通配符用于指定一个类型的上界,即泛型参数必须是该类型或其子类。这种通配符主要用于读取操作,因为它允许你安全地读取数据,但不允许你写入数据(除了null,因为null可以被视为任何类型的实例)。

特点:

add()方法:不能添加任何元素(除了null),因为编译器无法确定具体的类型,添加其他元素可能会导致类型安全问题。
get()方法:可以安全地读取元素,并且返回的类型是T或T的子类,但通常需要用T或T的父类(如Object)来接收,因为编译器无法确定具体的子类类型。
class Food { } class Fruit extends Food { } class Apple extends Fruit { } class Banana extends Fruit { } class Message<T> { private T message; public T getMessage() { return message; } public void setMessage(T message) { this.message = message; } } public class Test1 { public static void funExtends(Message<? extends Fruit> temp){ System.out.println(temp.getMessage()); //通配符的上界来说 是不可以进行修改元素的 /* temp.setMessage(new Banana()); temp.setMessage(new Apple());*/ //向上转型 Fruit fruit = temp.getMessage(); } public static void main(String[] args) { Message<Apple> message1 = new Message<>(); message1.setMessage(new Apple()); Message<Banana> message2 = new Message<>(); message2.setMessage(new Banana()); funExtends(message1); funExtends(message2); } }
 通配符下界
<? super 下界> 
下界通配符用于指定一个类型的下界,即泛型参数必须是该类型或其父类。这种通配符主要用于写入操作,因为它允许你安全地添加T或T的子类类型的元素,但在读取时只能确保是Object类型。 

特点:

add()方法:可以添加T或T的子类类型的元素,因为所有这些类型都是下界类型的子类或相同类型。
get()方法:读取元素时,由于类型的不确定性,通常只能用Object类型来接收。如果需要具体的类型,则需要进行类型转换。 
class Food { } class Fruit extends Food { } class Apple extends Fruit { } class Banana extends Fruit { } class Plate<T> { private T plate ; public T getPlate() { return plate; } public void setPlate(T plate) { this.plate = plate; } } public class Test1 { public static void funSuper(Plate<? super Fruit> temp){ // 此时可以修改!!添加的是Fruit 或者Fruit的子类 temp.setPlate(new Apple());//这个是Fruit的子类 向上转型 temp.setPlate(new Banana());//这个是Fruit的本身 // Fruit fruit = temp.getPlate(); //不能接收,这里无法确定是哪个父类 System.out.println(temp.getPlate());//只能直接输出 } public static void main(String[] args) { Plate<Fruit> message1 = new Plate<>(); Plate<Food> message2 = new Plate<>(); funSuper(message1); funSuper(message2); } }
泛型方法
语法
方法限定符 <类型形参列表> 返回值类型 方法名称(形参列表) { ... }
使用 
class Alg2 { //泛型方法 public static <T extends Comparable<T>> T findMax(T[] array) { T max = array[0]; for (int i = 1; i < array.length; i++) { if(array[i].compareTo(max) > 0) { max = array[i]; } } return max; } } public class Test2 { public static void main1(String[] args) { Integer[] array = {1,13,51,71,19}; Integer ret = Alg2.<Integer>findMax(array); System.out.println(ret); } }
泛型的限制
1. 不能使用基本数据类型作为泛型类型参数
Java中的泛型只能使用引用数据类型作为类型参数,不能使用基本数据类型(如int、double等)。如果需要使用基本数据类型的泛型,通常需要使用它们对应的包装类(如Integer、Double等)。

2. 不能创建泛型类型的数组
由于类型擦除的原因,Java不允许直接创建泛型类型的数组。例如,List<String>[] listArray = new ArrayList<String>[10]; 是不允许的。如果需要类似的功能,可以考虑使用ArrayList<List<String>>等集合类来实现。

3. 不能实例化泛型类型的对象(除了使用new操作符的匿名内部类)
Java不允许直接实例化泛型类型的对象,如List<String> list = new List<String>(); 是不允许的。应该使用具体的类来实例化泛型,如List<String> list = new ArrayList<>();。

4. 运行时类型查询的限制
由于类型擦除,在运行时无法直接查询泛型参数的具体类型。例如,instanceof 运算符和getClass()方法不能用于检查泛型类型参数的具体类型。这意味着,在运行时,所有的泛型类型都会被当作它们的原始类型(即擦除后的类型)来处理。

5. 泛型类型参数不具有继承关系
即使两个类之间存在继承关系,它们的泛型类型参数之间也不具有继承关系。例如,List<A>并不是List<B>的子类,即使A是B的子类。这要求开发者在编写泛型代码时特别注意类型安全。

6. 泛型上界和下界的限制
上界:通过extends关键字,可以限制泛型类型参数必须是某个类型的子类或实现类。这有助于在编译时检查类型兼容性,提高代码的安全性。
下界:通过super关键字,可以限制泛型类型参数必须是某个类型的父类型。这允许在泛型方法或类中灵活处理不同但兼容的类型。
7. 泛型通配符的限制
泛型通配符(如?、<? extends T>、<? super T>)用于表示未知类型或受限类型。然而,它们也带来了一些限制,如在使用上界通配符时不能添加除null以外的元素,而在使用下界通配符时读取的元素类型只能为Object等。

8. 反射和泛型
Java的反射机制可以在运行时访问类的信息,但由于类型擦除,反射无法直接获取泛型类型参数的具体信息。这要求开发者在使用反射和泛型时需要特别注意类型安全和类型转换的问题。

Read more

用 10% GPU 跑通万亿参数 RL!马骁腾拆解万亿参数大模型的后训练实战

用 10% GPU 跑通万亿参数 RL!马骁腾拆解万亿参数大模型的后训练实战

整理 | 梦依丹 出品 | ZEEKLOG(ID:ZEEKLOGnews) 左手是提示词的工程化约束,右手是 Context Learning 的自我进化。 在 OpenAI 新发布的《Prompt guidance for GPT-5.4》中,反复提到了 Prompt Contracts(提示词合约)。要求开发者像编写代码一样,严谨地定义 Agent 的输入边界、输出格式与工具调用逻辑,进而换取 AI 行为的确定性。 但在现实操作中,谁又能日复一日地去维护那些冗长、脆弱的“提示词代码”? 真正的 Agent,不应只靠阅读 Context Engineering,更应该具备 Context Learning 的能力。 为此,在 4 月 17-18

By Ne0inhk
当OpenClaw引爆全网,谁来解决企业AI Agent的“落地焦虑”?

当OpenClaw引爆全网,谁来解决企业AI Agent的“落地焦虑”?

2026 年 3 月,开源 AI Agent 框架 OpenClaw 在 GitHub 上的星标突破28万,并一度超越 React,成为 GitHub 最受关注的软件项目之一。短时间内,开发者利用它构建了大量实验性应用:从全栈开发辅助,到自动化营销脚本,再到桌面操作自动化,AI Agent 的能力边界正在迅速被拓展。 这股热潮也带动了另一个趋势——本地部署与算力硬件需求的快速增长。越来越多开发者尝试在个人设备或企业服务器上运行 Agent 系统,以获得更高的控制权和数据安全性。 从表面上看,AI Agent 似乎正从“概念验证”走向更广泛的开发实践。但在企业环境中,情况却没有想象中乐观。当企业负责人开始追问—— “它能直接解决我的业务问题吗?” 很多演示级产品仍难以给出令人满意的答案。 如何让 Agent 真正融入企业既有系统、适配复杂业务流程,正成为大模型产业落地必须跨越的一道门槛。 与此同时,中国不同城市的产业结构差异明显:互联网、

By Ne0inhk
二手平台出现OpenClaw卸载服务,299元可上门“帮卸”;2026年春招AI人才身价暴涨:平均月薪超6万;Meta辟谣亚历山大·王离职 | 极客头条

二手平台出现OpenClaw卸载服务,299元可上门“帮卸”;2026年春招AI人才身价暴涨:平均月薪超6万;Meta辟谣亚历山大·王离职 | 极客头条

「极客头条」—— 技术人员的新闻圈! ZEEKLOG 的读者朋友们好,「极客头条」来啦,快来看今天都有哪些值得我们技术人关注的重要新闻吧。(投稿或寻求报道:[email protected]) 整理 | 苏宓 出品 | ZEEKLOG(ID:ZEEKLOGnews) 一分钟速览新闻点! * 微信员工辟谣“小龙虾可自动发红包”:不要以讹传讹 * 蚂蚁集团启动春招,超 70% 为 AI 相关岗位 * 受贿 208 万!拼多多一员工被抓 * 2026 年春招 AI 人才身价暴涨: 平均月薪超 6 万元 * 二手平台出现 OpenClaw 上门卸载服务 * 权限太高,国家互联网应急中心发布 OpenClaw 安全应用的风险提示 * 字节豆包内测 AI 电商功能:无需跳转抖音,日活用户数超

By Ne0inhk
遭“美国政府封杀”后,Anthropic正式提起诉讼!

遭“美国政府封杀”后,Anthropic正式提起诉讼!

整理 | 苏宓 出品 | ZEEKLOG(ID:ZEEKLOGnews) 据路透社报道,当地时间周一,AI 初创公司 Anthropic 正式对美国国防部及特朗普政府提起诉讼,抗议五角大楼将其列为“国家安全供应链风险”主体的决定。 Anthropic 在向美国加州北区地方法院提交的诉讼文件中表示,这一认定“史无前例且非法”,已对公司造成“不可挽回的损害”。公司希望法院撤销该决定,并指示联邦机构停止执行相关认定。 划定 AI 应用红线,双方观点不一 正如我们此前报道,这场争端的核心在于 Anthropic 为其核心 AI 模型 Claude 设定的两条技术使用红线,与美国国防部的使用需求发生根本冲突。 此前,Anthropic 曾与五角大楼签署一份价值最高可达 2 亿美元的合作合同,Claude 也成为少数被纳入美国机密网络环境进行测试的 AI 系统之一。 对此,Anthropic 一直坚持两条底线: * Claude 等技术不得被用于对美国民众的大规模国内监控;

By Ne0inhk