Java这个高级特性,很多人还没用过!
开发者技术前线
共 11299字,需浏览 23分钟
· 2021-05-29
点击“开发者技术前线”,选择“星标🔝”
让一部分开发者看到未来 来源 | https://zhenbianshu.github.io/
前言
泛型是什么
generic
,中文意思是通用的、一类的,结合其应用场景,我理解泛型是一种 通用类型
。但我们一般指泛型都是指其实现方式,也就是 将类型参数化
public static void quickSort(int[] data, int start, int end) {
int key = data[start];
int i = start;
int j = end;
while (i < j) {
while (data[j] > key && j > i) {
j--;
}
data[i] = data[j];
while (data[i] < key && i < j) {
i++;
}
data[j] = data[i];
}
data[i] = key;
if (i - 1 > start) {
quickSort(data, start, i - 1);
}
if (i + 1 < end) {
quickSort(data, i + 1, end);
}
}
public static <T extends Comparable<T>> void quickSort(T[] data, int start, int end) {
T key = data[start];
int i = start;
int j = end;
while (i < j) {
while (data[j].compareTo(key) > 0 && j > i) {
j--;
}
data[i] = data[j];
while (data[i].compareTo(key) < 0 && i < j) {
i++;
}
data[j] = data[i];
}
data[i] = key;
if (i - 1 > start) {
quickSort(data, start, i - 1);
}
if (i + 1 < end) {
quickSort(data, i + 1, end);
}
}
当参数类型不明确,可能会扩展为多种时。 想声明参数类型为 Object
,并在使用时用instanceof
判断时。
泛型只能替代Object的子类型
,如果需要替代基本类型,可以使用包装类,至于为什么,会在下文中说明。使用
声明
<占位符 [,另一个占位符] >
的形式,需要在一个地方同时声明多个占位符时,使用 ,
隔开。占位符的格式并无限制,不过一般约定使用单个大写字母,如 T 代表类型(type),E 代表元素*(element)等。虽然没有严格规定,不过为了代码的易读性,最好使用前检查一下约定用法。class Generics<T> { // 在类名后声明引入泛型类型
private T field; // 引入后可以将字段声明为泛型类型
public T getField() { // 类方法内也可以使用泛型类型
return field;
}
}
public [static] <T> void testMethod(T arg) { // 访问限定符[静态方法在 static] 后使用 <占位符> 声明泛型方法后,在参数列表后就可以使用泛型类型了
// doSomething
}
Comparable<T>
的泛型接口,与此类似的还有 Searializable<T> Iterable<T>
等,其实在接口中声明与在类中声明并没有什么太大区别。调用
public static void main(String[] args) {
String[] strArr = new String[2];
// 泛型方法的调用跟普通方法相同
Generics.quickSort(strArr, 0, 30 );
// 泛型类在调用时需要声明一种精确类型
Generics<Long> sample = new Generics<>();
Long field = sample.getField();
}
// 泛型接口需要在泛型类里实现
class GenericsImpl<T> implements Comparable<T> {
@Override
public int compareTo(T o) {
return 0;
}
}
类型擦除
由来
Generics<Long>
被擦除后是 Generics
,我们常用的 List<String>
被擦除后只剩下 List
。public static void main(String[] args) {
List<String> stringList = new ArrayList<>();
List<Long> longList = new ArrayList<>();
if (stringList.getClass() == longList.getClass()) {
System.out.println(stringList.getClass().toString());
System.out.println(longList.getClass().toString());
System.out.println("type erased");
}
}
class java.util.ArrayList
,两者类型相同,说明其泛型类型被擦除掉了。signature
字段,其中指向了常量表中泛型的真正类型,所以泛型的真正类型,还可以通过反射获取得到。实现
javac
命令编译成 class 文件后,再使用 javap
命令查看其字节码信息:T
被替换成了 Object 类型,而在 main
方法里 getField
字段时,进行了类型转换(checkcast
),如此,我们可以看出来 Java 的泛型实现了,一段泛型代码的编译运行过程如下:编译期间编译器检查传入的泛型类型与声明的泛型类型是否匹配,不匹配则报出编译器错误; 编译器执行类型擦除,字节码内只保留其原始类型; 运行期间,再将 Object 转换为所需要的泛型类型。
Java 的泛型实际上是由编译器实现的,将泛型类型转换为 Object 类型,在运行期间再进行状态转换
。实践问题
具体类型须为Object子类型
Generics<int> generics = new Generics<int>();
在编译期间就会报错的。边界限定通配符的使用
<? extends Generics>
是上边界限定通配符,避开 上边界
这个比较模糊的词不谈,我们来看其声明 xx extends Generics
, XX 是继承了 Generics 的类(也有可能是实现,下面只说继承),我们按照以下代码声明:List<? extends Generics> genericsList = new ArrayList<>();
Generics generics = genericsList.get(0);
genericsList.add(new Generics<String>()); // 编译无法通过
<? super Generics>
是下边界限定通配符, XX 是 Generics 的父类,所以:List<? super Generics> genericsList = new ArrayList<>();
genericsList.add(new Generics()); // 编译无法通过
Generics generics = genericsList.get(0);
最佳实践
将代码逻辑拆分为两部分:通用逻辑和类型相关逻辑;通用逻辑是一些跟参数类型无关的逻辑,如快排的元素位置整理等;类型相关逻辑,顾名思义,是需要确定类型后才能编写的逻辑,如元素大小的比较,String 类型的比较和 int 类型的比较就不一样。 如果没有类型相关的逻辑,如 List 作为容器不需要考虑什么类型,那么直接完善通用代码即可。 如果有参数类型相关的逻辑,那么就需要考虑这些逻辑是否已有共同的接口实现,如果已有共同的接口实现,可以使用边界限定通配符。如快排的元素就实现了 Compare
接口,Object 已经实现了toString()
方法,所有的打印语句都可以调用它。如果还没有共同的接口,那么需要考虑是否可以抽象出一个通用的接口实现,如打印人类的衣服颜色和动物的毛皮颜色,就可以抽象出一个 getColor()
接口,抽象之后再使用边界限定通配符。如果无法抽象出通用接口,如输出人类身高或动物体重这种,还是不要使用泛型了,因为不限定类型的话,具体类型的方法调用也就无从谈起,编译也无法通过。
小结
— 完 —
点这里👇关注我,记得标星呀~
前线推出学习交流一定要备注:研究/工作方向+地点+学校/公司+昵称(如JAVA+上海+上交+可可),根据格式备注,可更快被通过且邀请进群
扫码加小编微信,进群和大佬们零距离
END 后台回复“电子书” “资料” 领取一份干货,数百面试手册等你 开发者技术前线 ,汇集技术前线快讯和关注行业趋势,大厂干货,是开发者经历和成长的优秀指南。 历史推荐
腾讯 Code Review 规范出炉! 一场由MyBatis版本升级引发的线上惨案 Spring 官宣,抛弃原生 JVM! 我见过最“骚”的代码注释!神兽版都来了 好文点个在看吧!
评论
JS的这些新特性,你都用过么?
大厂技术 高级前端 Node进阶点击上方 程序员成长指北,关注公众号回复1,加入高级Node交流群作为一门不断演进的语言,JavaScript每年都会引入新特性。这些特性的加入,能够帮助我们编写更加简洁、高效、易于维护的代码。然而,并非所有新特性
程序员成长指北
1
豆瓣9.7,这部Java神作第3版重磅上市!
文末赠书Java 程序员们开年就有重磅好消息,《Effective Java 中文版(原书第 3 版)》要上市啦!该书的第1版出版于 2001 年,当时就在业界流传开来,受到广泛赞誉。时至今日,已热销近20年,本书第 3 版已是 Java 程序员的必读神书,被誉为“Java 四大名著之一”,甚至连
编码之外
0
大量 Java 开源项目停更...
点击关注公众号,Java 干货及时推送↓推荐阅读:投了 100 多份简历后…出品 | OSC开源社区(ID:oschina2013)Sonatype 发布了最新的一份《软件供应链状况》报告,深入探讨了如何在充满选择的世界中定义更好的软件,并探讨人工智能 (AI) 对软件开发的深远
Java技术栈
0
10个高级的 SQL 查询技巧
来源:towardsdatascience.com/ten-advanced-sql-concepts-you-should-know-for-data-science-interviews-4d7015ec74b0👉 欢迎加入小哈的星球 ,你将获得: 专属的项目实战 / Jav
小哈学Java
0
Java 神作,必读!
Java 程序员们开年就有重磅好消息,《Effective Java 中文版(原书第 3 版)》要上市啦!该书的第1版出版于 2001 年,当时就在业界流传开来,受到广泛赞誉。时至今日,已热销近20年,本书第 3 版已是 Java 程序员的必读神书,被誉为“Java 四大名著之一”,甚至连 Java
小哈学Java
0
Java与lua互相调用简单教程
来源:网络👉 欢迎加入小哈的星球 ,你将获得: 专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡 / 赠书福利全栈前后端分离博客项目 2.0 版本完结啦, 演示链接:http://116.62.199.48/ ,新项目
小哈学Java
0
【送书福利】《Java面试八股文:高频面试题与求职攻略一本通》
先来唠唠最近粉丝面试回来跟我聊天,基本上都提到一个点,在面试过程中八股文占比很高(八股文70%、项目20%、10%算法)除了一些搞算法突出的厂除外。其实现在很多厂八股都是逐渐深入的方式来问,所以大家在学习的过程中,针对一些重点的内容,最好深入去学习,不然还是比较难应对这种追问式的问题。最近刚好从一位
Java后端技术
0
大家避雷这个软件!!
“软件分享”只分享好玩有趣的黑科技软件大家避雷这个软件,因为实在是太好用啦!兄弟们,今天我要向大家介绍一个神奇的网站,它在我们的日常生活和工作中都起到重要作用,它能够帮我们解决生活中的很多难题。在你无助时你可以与它进行
一锅汤软件
3