泛型趣谈

Java中的泛型带来了什么好处?规约。就像接口定义一样,可以帮助对于泛型类型和对象的使用上,保证类型的正确性。如果没有泛型的约束,程序员大概需要在代码里面使用大量的类型强制转换语句,而且需要非常清楚没有标注的对象实际类型,这是容易出错的、恼人的。但是话说回来,泛型可不只有规约,还有很多有趣的用法,容我一一道来。

 

泛型擦除

Java的泛型在编译阶段实际上就已经被擦除了(这也是它和C#泛型最本质的区别),也就是说,对于使用泛型的定义,对于编译执行的过程,并没有任何的帮助(有谁能告诉我为什么按着泛型擦除来设计?)。所以,单纯利用泛型的不同来设计接口,会遇到预期之外的问题,比如说:

1
2
3
4
public interface Builder<K,V> {
     public void add(List<K> keyList);
     public void add(List<V> valueList);
}

想这样设计接口?仅仅靠泛型类型的不同来设计重载接口?那是痴人说梦。但是如果代码变成这样呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class GenericTypes {
 
     public static String method(List<String> list) {
         System.out.println( "invoke method(List<String> list)" );
         return "" ;
     }
 
     public static int method(List<Integer> list) {
         System.out.println( "invoke method(List<Integer> list)" );
         return 1 ;
     }
 
     public static void main(String[] args) {
         method( new ArrayList<String>());
         method( new ArrayList<Integer>());
     }
}

这个情况就有点特殊了,Sun的Javac编译器居然可以通过编译,而其它不行,这个例子来自IcyFenix的文章,有兴趣不妨移步参阅IcyFenix的文章以及下面的讨论。

 

方法泛型

在JDK的java.util.List接口里面,定义了这样一个方法:

1
2
3
public interface List<E> extends Collection<E> {
     <T> T[] toArray(T[] a);
}

事实上,这个方法泛型T表示的是任意类型,它可是和此例中的接口/类泛型E毫不相干啊。

如果我去设计方法,我可能写成这样:

1
<T> T[] toArray();

其实这个T[ ] a参数的作用也容易理解:

  1. 确定了数组类型;
  2. 如果给定的数组a能够容纳得下结果,就会把结果放进a里面(JDK的注释有说明“If the list fits in the specified array, it is returned therein.”),同时也把a返回。

如果没有这个T[ ] a参数的话,光光定义一个方法泛型<T>是没有任何意义的,因为这个T是什么类型完全是无法预料的,例如:

1
2
3
4
5
6
7
8
9
public class Builder {
     public <E> E call(){
         return null ;
     }
     
     public static void main(String[] args) {
         String s = new Builder().call(); // ①
         Integer i = new Builder().call(); // ②
         new Builder().<String>call(); // ③
1
2
     }
}

可以看到,call()方法返回的是类型E,这个E其实没有任何约束,它可以表示任何对象,但是代码上不需要强制转换就可以赋给String类型的对象s(①),也可以赋给Integer的对象i(②),甚至,你可以主动告知编译器返回的对象类型(③)。

 

链式调用

看看如下示例代码:

1
2
3
4
5
6
7
8
9
public class Builder<S> {
     public <E> Builder<E> change(S left, E right){
         // 省略实现
     }
     
     public static void main(String[] args) {
         new Builder<String>().change( "3" , 3 ).change( 3 , 3 .0f).change( 3 .0f, 3 .0d);
     }
}

同样一个change方法,接收的参数变来变去的,上例中方法参数从String-int变到int-float,再变为float-double,这样的泛型魔法在设计链式调用的方法的时候,特别是定义DSL语法的时候特别有用。

 

使用问号 

其实问号帮助表示的是“通配符类型”,通配符类型 List<?> 与原始类型 List 和具体类型 List<String>都不相同,List<?>表示这个list内的每个元素的类型都相同,但是这种类型具体是什么我们却不知道。注意,List<?>和List<Object>可不相同,由于Object是最高层的超类,List<Object>表示元素可以是任何类型的对象,但是List<?>可不是这个意思。

来看一段有趣的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Wrapper<E> {
     private E e;
     public void put(E e) {
         this .e = e;
     }
     
     public E get(){
         return e;
     }
}
 
public class Builder {
     public void check(Wrapper<?> wrapper){
         System.out.println(wrapper.get()); // ①
         wrapper.put( new Object()); // ② wrong!
         wrapper.put(wrapper.get()); // ③ wrong!
         wrapper.put( null ); // ④ right!
     }
}

Wrapper的类定义里面指定了它包装了一个类型为E的对象,但是在另一个使用它的类Builder里面,指定了Wrapper的泛型参数是?,这就意味着这个被包装的对象的类型是完全不可知的:

  • 现在我可以调用Wrapper的get方法把对象取出来看看(①),
  • 但是我不能放任意类型确定的对象进去,Object也不行(②),
  • 即便是从wrapper里面get出来也不行(编译器太不聪明了是吧?③)
  • 可奇葩的是,放一个null是可以被允许的,因为null根本就不是任何一个类型的对象(④,注意,不能放int这类的原语类型,虽然它不是对象,但因为它会被自动装箱成Integer,从而变成具体类型,所以是会失败的)。

现在思考一下,如果要表示这个未知对象是某个类的子类,上面代码的Wrapper定义不变,但是check方法写成:

1
public void check(Wrapper<? extends String> wrapper){
1
wrapper.put( new String());
1
}

这样呢?

……

依然报错,因为new String()确实是String的子类(或它自己)的对象,一点都没错,但是它可不见得和同为String子类(或它自己)的“?”属于同一个类型啊!

如果写成这样呢(注意extends变成了super)?

1
public void check(Wrapper<? super String> wrapper){
1
wrapper.put( new String());
1
}

这次对了,为什么呢?

……

因为wrapper要求put的参数“?”必须是String的父类(或它自己),而不管这个类型如何变化,它一定是new String()的父类(或它自己)啊!

 

泛型递归

啥,泛型还能递归?当然能。而且这也是一种好玩的泛型使用:

1
2
3
4
5
6
7
8
class Wrapper<E extends Wrapper<E>> implements Comparable<Wrapper<E>> {
 
     @Override
     public int compareTo(Wrapper<E> wrapper) {
         return 0 ;
     }
 
}

好玩吧?泛型也能递归。这个例子指的是,一个对象E由包装器Wrapper所包装,但是,E也必须是一个包装器,这正是包装器的递归;同时,包装器也实现了一个比较接口,使得两个包装器可以互相比较大小。

 

别晕!泛型只不过是一个普普通通的语言特性,但是也挺有趣的。

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接《四火的唠叨》

从零到一:YOLOv11高帧率模型在RDK X5上的ONNX转换与部署实战 本文详细介绍了将最新的YOLOv11高帧率模型部署到地平线RDK X5开发板的完整实战流程。内容涵盖从PyTorch模型导出ONNX、地平线工具链环境配置与模型量化编译,到编写高效的板端推理代码,并针对高帧率目标进行了后处理优化。通过实战避坑指南,帮助开发者在RDK X5上实现30FPS以上的实时目标检测。 阅读详情

相关推荐

Allegro PCB设计实战:5分钟搞定DDR信号线的Match Group等长规则设置

本文详细介绍了在Allegro PCB设计中,如何快速为DDR信号线设置Match Group等长规则。通过实战演练,解析了从理解相对传输延迟原理、在规则管理器中创建Match Group,到设置合理容差和利用动态绕线指示的全流程,帮助工程师在5分钟内高效完成高速信号时序约束,提升设计可靠性与效率。

gg901的博客 1055

深入理解Java虚拟机——程序编译与代码优化 (转)

一早期(编译期)优化   1概述   Java语言的“编译期”是一段“不确定”的操作过程,因为它可能是指一个前端编译器(其实叫“编译器的前端”更准确一些)把*.java文件转变成*.class文件的过程;也可能是指虚拟机的后端运行期编译器(JIT编译器,just in time compiler)把字节码转变成机器码的过程;还可能是指使用静态提前编译器(AOT编译器,ahead of t...

xiaomin1991222的专栏 389

机械臂的运动学分析-工业机器人

机械臂的运动学是研究机械臂各连杆坐标系之间的运动关系,是对机械臂进行运动控制的基础。本章分析了所设计的六自由度机械臂的运动学。理论上六自由度机械臂的工作空间是一个近似球形区域,能够覆盖机械臂所在的位置,但由于机械臂关节的运动范围受到限制,机械臂末端会存在一些不能到达的工作死区,使得机械臂的工作范围和灵活性受到限制。理论上六自由度机械臂的工作空间是一个近似球形区域,能够覆盖机械臂所在的位置,但由于机械臂关节的运动范围受到限制,机械臂末端会存在一些不能到达的工作死区,使得机械臂的工作范围和灵活性受到限制。

qq_59137727的博客 6648

第一章 数据类型趣谈

目录 1 值类型与引用类型 1.1 线程堆栈和托管堆 1.2 引用类型变量的内存模型 1.3 “=” 和 “==” 辨析 1.4 装箱与拆箱 2 说不尽的字符串 3 数据类型的模板化——泛型 1 值类型与引用类型 1.1 线程堆栈和托管堆 值类型:int、double、enum、struct 引用类型:类、接口、数组、委托、String 值类型变量与引用型变量的内存分配模型...

Devin的博客 380

【新华三】通过路由复制实现Public与VRF路由互通

如上图所示,S6900设备里有两张表,一张是public路由表,默认所有的路由都存放在public路由表里;除此之外还创建了VRF test,因此此设备还有VRF test路由表。通过路由复制实现Public路由和VRF路由互通,默认情况下VRF里的路由单独一张路由表,默认情况下与public路由表相互隔离,两张表之间不可互访。此时的public路由表里面并没有test的路由表。public路由表与VRF路由表之间相互隔离。此时VRF test里的路由也没有其他VRF或Public里的路由,相互隔离。

五大连池的镜子 5279

数理逻辑1 -- 命题演算1

一直对逻辑的东西很感兴趣,尤其最近做的东西和AI相关,因此下定决心系统地学习数理逻辑。这些笔记并不是严谨的描述,只是作为一些概念的快速参考,以及加入一些个人认为好玩的公式、定理和推导。 简单来说,数理逻辑系统是由一串“符号”组成的系统,基本元素是那一堆“符号”,由“符号”组成“式子”。逻辑系统并不关心“式子”是否对错,只关心“式子”是否存在,也即是假定存在某些“式子“,再确定”推导规则“(Rule

Jason渣神的专栏 1831

Java 便利贴之泛型

为什么要使用泛型?泛型是什么?怎么用?

樱木天亥 431

光储微电网混合储能系统的控制策略

随着社会生产力的不断提高,对不可再生资源的大量消耗,人们已经意识到发展可再生能源的重要性,因此微电网技术作为再生能源利用的有效形式被快速发展。蓄电池容量无限大是传统光储微电网混合储能系统控制策略一种理想形式,但实际上蓄电池的容量是有限度的,传统控制策略在蓄电池剩余电量达到阖值时将无法正常使用,由此提出了光储微电网混合储能系统的新型控制策略,又结合实际情况,对开关进行了改进,利用开关与二极管并联,使其拥有四种工作状态,当储能元件剩余电量达到阈值时,可自动恢复电量降低成本,提高并输出电池电能质量。

nhkg888的博客 1742

java pdf添加便利贴_Java 便利贴之泛型

为什么要使用泛型?Java 语言以严谨著称,但在设计的时候忽略了「泛型」这个重要的概念,增加了使用者的责任,使用者需要记住每个元素的类型,同时还得强制转型,编译器无法帮忙,在运行时才会抛出 Class Cast 异常。泛型是什么?Java 5 以后,引入了参数化类型(parameterized type),Java 的参数化类型被称为泛型(Generic)。所谓泛型,就是允许在定义类、接口、方法时...

weixin_42322512的博客 110

Hermes V0.10.0:官方UI几乎无Bug版

如果你还在观望Hermes,现在可能是最好的入局时机。 因为网页端来了,门槛降到了最低。 如果你已经是Hermes用户,升级就对了。 因为0.9.0的更新,值得一试。

weixin_66295112的博客 2046

OpenClaw 2026 路线图详解:3 大协作能力升级与社区贡献增长 62% 的实证分析

介绍 OpenClaw 2026 如何通过上下文锚定(Context Anchoring)、协作质量定义和责任边界机制,将 AI 编程工具从单点补全升级为嵌入代码生命周期的协作对齐系统,并详解 `.openclaw/config.yaml` 中 `context_anchor` 配置的实操方法与效果

weixin_42545292的博客 384

Java泛型

泛型传递 最近在读代码的过程中,经常遇到一些利用泛型来对调用链中的参数进行类型约束的情形,特指对于调用链中后面环节的参数类型和返回值,由前面环节的参数类型来确定,我草率地把它称作泛型传递(技巧很简单,但是用得好会很有趣;我不知道这个东西正儿八经的名字叫做什么)。 在说这个事情以前,对于Java的泛型,还是和其它语言中有些许的不同,这里需要结合使用方法泛型和类泛型,如有不明,对于其中的使用

qq_28582697的博客 321

logisim中,如何设计一个位于十字路口的交通信号灯控制系统?

🏆本文收录于 《全栈 Bug 调优(实战版)》 专栏。专栏聚焦真实项目中的各类疑难 Bug,从成因剖析 → 排查路径 → 解决方案 → 预防优化全链路拆解,形成一套可复用、可沉淀的实战知识体系。无论你是初入职场的开发者,还是负责复杂项目的资深工程师,都可以在这里构建一套属于自己的「问题诊断与性能调优」方法论,助你稳步进阶、放大技术价值。

**My Coding Family** 1345

趣谈ThreadLocal

趣谈ThreadLocal 来源:趣谈编程 作者:趣谈编程 趣谈ThreadLocal

橙子君的博客 238

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

《电子入门趣谈》续更

续更《电子入门趣谈》

zbl_learn的博客 788

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

生肖趣谈

生肖趣谈(陈勤建)(上海古籍出版社)     在我国,以天干地支纪年,由来已久。但是后来流传中出现了生肖,有十二兽附会其上,以至于人们对自己的生辰更习惯于用十二兽来表示,生肖和我们的关系以及生肖的习尚与我们的生命联系在一起常常令人们百思不得其解。 形式上,生肖是我们古人纪年岁的一种方式,但是实际上,生肖是我们民族文化生命的重要标识。人类如果只对自身的生物生命有所了解,而对文化生命一知半解,那么

Rookie_hh的博客 947

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

【亲测免费】 趣谈网络协议资源下载:轻松掌握网络协议的核心秘密

趣谈网络协议资源下载:轻松掌握网络协议的核心秘密 去发现同类优质开源项目:https://gitcode.com/ 在数字化时代,网络协议是连接世界的基石。理解网络协议的工作原理和实际应用,对技术人员而言至关重要。今天,我要为大家推荐一个开源项目——趣谈网络协议资源下载,它以独特的视角和生动的方式,帮助你轻松掌握网络协议的核心知识。 项目介绍 趣谈网络协议资源下载项目,提供了一份名为《014-趣谈...

gitblog_06765的博客 811

企业文化趣谈

趣谈一:回应 该企业内部互相提意见、缺点指正、批评时一般不会让你很难堪很尴尬,更不会让你火冒三丈。因为他们用了一个很文雅很有人情味的两个字:回应! 不管是员工还是领导,在某些方面作得不好时,都可以说:“某某,我给你一个回应”。被回应者一般都会笑着说:“好啊,你说”。于是一二三五六七之后,对的点头接受并真诚致谢,感觉还有点不那么回事的或需解释的,好了,这就又是我下面要谈的趣谈二,我们可以就这问题...

beifenggo 105

趣谈网络协议资源下载介绍

趣谈网络协议资源下载介绍 去发现同类优质开源项目:https://gitcode.com/ 欢迎来到我们的资源下载仓库!此仓库为您提供了一项珍贵的资源——《014-趣谈网络协议》。这是一份深入浅出地解析网络协议的资料,旨在帮助读者更好地理解网络协议的工作原理及其在实际应用中的重要性。 该资源文件以幽默风趣的方式,将复杂的网络协议知识讲解得通俗易懂,无论是网络技术的初学者还是有一定基础的技术人员,都...

gitblog_06774的博客 341

趣谈Linux操作系统资源下载说明:轻松学习Linux的宝藏资源

趣谈Linux操作系统资源下载说明:轻松学习Linux的宝藏资源 去发现同类优质开源项目:https://gitcode.com/ 项目介绍 在众多开源操作系统中,Linux以其强大的功能和灵活性获得了无数开发者和爱好者的青睐。然而,对于初学者来说,Linux复杂的命令和概念可能会让人望而却步。《趣谈Linux操作系统资源下载说明》正是为此而生,它以幽默风趣的方式,将Linux的知识点变得生动有趣...

gitblog_06755的博客 391

趣谈Linux操作系统资源下载说明

趣谈Linux操作系统资源下载说明 去发现同类优质开源项目:https://gitcode.com/ 欢迎来到本资源仓库!本仓库提供了《趣谈Linux操作系统》的资源文件,以便对Linux操作系统有兴趣的爱好者能够更轻松愉悦地学习Linux。 资源简介 资源文件名为“趣谈Linux操作系统.zip”,其中包含了一系列关于Linux操作系统的精彩内容。文件通过幽默风趣的语言风格,将复杂的Linux知...

gitblog_06710的博客 420

我与量子趣谈的“孽缘”

选这门课时过程的坎坷大概已经预示了些什么,不过没想到它没预示过程,只预示了结尾。很久之前就对量子什么的很感兴趣,像多宇宙理论,超弦理论之类的,听着就很有意思,跟别人聊天说到这些的话也会显得自己很厉害的样子。不过只是单纯的感兴趣,真正了解的知识几乎没有,所以选课前看到有量子趣谈这门课很开心,选修的话应该是以拓展知识为主,不会太专业,这么想的我已经下定决...

weixin_34240520的博客 160

清酿酒之家元宇宙 酒型人格趣谈:你的性格,酒知道

这类人在工作和生活中都表现出强烈的领导力和决策能力,他们敢于面对挑战,不怕失败,勇于担当,善于创新,总能在困难中找到突破口,带领团队走出困境。同时,白酒型人格的人也非常直率,喜欢直来直去,不拐弯抹角,这种坦率的性格也让他们在人际交往中备受尊重。米酒型人格的人性格纯真、可爱且待人真诚。红酒型人格的人,通常性格较为内敛,举止优雅,气质高贵,善于观察和思考,对事物有着敏锐的洞察力。这类人在工作和生活中都表现出极强的创造力和想象力,他们善于从不同的角度思考问题,总能找到新的解决方案,也乐于尝试新鲜事物和挑战自我。

qq_33865146的博客 436
上一篇: java.util.concurrent并发包诸类概览
RayChase
博客等级 码龄20年 71粉丝 87原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值