深入Java泛型及其设计原则
在日常开发中,必不可少的会使用到泛型,这个过程中经常会出现类似“为什么这样会编译报错?”,“为什么这个列表无法添加元素?”的问题,也会出现感叹Java的泛型限制太多了很难用的情况。为了更好的使用泛型,就需要更深的了解它,因此本文主要介绍泛型诞生的前世今生,特性,以及著名PECS原则的由来。
▐ 背景
在没有泛型之前,必须使用Object编写适用于多种类型的代码,想想就令人头疼,并且非常的不安全。同时由于数组的存在,设计者为了让其可以比较通用的进行处理,也让数组允许协变,这又为程序添加了一些天然的不安全因素。为了解决这些情况,Java的设计者终于在Java5中引入泛型,然而,正是因为引入泛型的时机较晚,为了兼容先前的代码,设计者也不得不做出一些限制,来让使用者(也就是我们)以难受换来一些安全。
▐ 优点
-
程序更加易读 -
安全性有所保证
import java.util.ArrayList;
import java.util.Date;
public class Main {
public static void main(String[] args) {
ArrayList list = new ArrayList();
//强制类型转换
String res = (String) list.get(0);
//十分不安全的行为
list.add(new Date());
}
}
这种写法在编译类型时不会报错,但一旦使用get获取结果并试图将Date转换为其他类型时,很有可能出现类型转换异常,为了解决这种情况,类型参数应用而生。
▐ 类型参数
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<String> objects = new ArrayList<>();
objects.add("Hello");
}
}
这使得代码具有更好的可读性,并且在调用get()的时候,无需进行强转,最重要的是,编译器终于可以检查一个插入操作是否符合要求,运行时可能出现的各种类型转换错误得以在编译阶段就被阻止。
import java.util.ArrayList;
import java.util.Date;
public class Main {
public static void main(String[] args) {
ArrayList<String> objects = new ArrayList<>();
//we can do it like that
objects.add("Hello");
//wrong example
objects.add(new Date());
}
}
![]()
基本用法
▐ 泛型类
public class Animal<T> {
private String name;
private T mouth;
public T getMouth(){
return mouth;
}
}
public class Animal<T,U> {
private String name;
private T mouth;
private U eyes;
public T getMouth(){
return mouth;
}
}
▐ 泛型方法
public class Animal<T,U> {
private T value;
public static <T> T get(T... a){
return a[a.length-1];
}
public T getFirst(){
return value;
}
}
![]()
类型擦除
▐ 强制转换
public class Main {
public static void main(String[] args) {
Animal<Integer,Double> pair = new Animal<>();
Integer first = pair.getFirst();
}
}
-
对原始方法的调用。 -
将返回的Object类型强制转换为Integer类型。
▐ 方法桥接
图片来源:RudeCrab
▐ 总结
-
虚拟机中没有泛型,只有普通的类和方法。 -
所有的类型参数都会替换为他们的限定类型。 -
会合成桥接方法来保持多态。 -
为保持类型安全性,必要时会插入强制类型转换。
变型与数组
-
则f(Dog)是f(Animal)的子类,称为协变; -
则f(Dog)是f(Animal)的父类,成为逆变; -
则f(Dog)和f(Animal)没有任何关系;
▐ 上界
到这里可以顺便说一下集合的设计,可以注意到集合中只有add方法是泛型参数,而其余方法并不是,为何要这样设计,为何不把其余方法的参数类型也改为E?其原因就是在于,如果将contains和remove改为E,那么声明上界之后,调用这两个方法会引发编译错误,然而这两个方法均为类型安全方法,自然不可声明为E,add作为很明显的写方法,自然也需要用E作为参数类型,到这里,不得不感叹类库设计者的想法独到。
▐ 下界
▐ PECS
结语
泛型的引入极大地提高了代码的安全性和可读性,但同时也带来了一些限制和挑战。特别是类型擦除机制,虽然保证了向后兼容性,但也导致了一些潜在的问题,如不能实例化类型参数和不能使用基本类型等。
在实际开发中,掌握泛型的基本用法和高级特性,如PECS原则,对于编写高效、安全的代码至关重要。通过合理使用泛型,我们可以避免许多常见的类型转换错误,提高代码的健壮性和可维护性。希望本文能帮助读者更好地理解和应用Java泛型,从而在日常开发中更加得心应手。
本文分享自微信公众号 - 大淘宝技术(AlibabaMTT)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
北京人工智能产业核心产值突破 2686 亿元
北京青年报发文指出,目前北京人工智能学者已超过1.5万人,占全国30.6%。张宏江、朱松纯、鄂维南、陆奇、李开复、王小川等全球人工智能顶尖人才在京创业或组建研发机构。北京有14所高校设立了人工智能学院或研究院,25所高校获批人工智能本科专业,27所高校拥有相关学科的硕、博点。 这些顶级资源产生强大动力。2010至2023年上半年,北京学者在人工智能领域国际顶会和顶刊上发表论文数量约2.6万篇,占全国约四成;截至去年底,北京企业在人工智能领域授权发明专利数量13.1万件,占全国约两成,综合创新能力国内领先。 从企业数量来看,中国信通院数据显示,北京人工智能企业1332家,占全国30%。北京拥有人工智能独角兽企业42家。2023年北京人工智能产业核心产值突破2686亿元。 此外,北京的人工智能产业链布局完整,覆盖基础层、技术层、应用层全链条。基础层方面,寒武纪、摩尔线程、昆仑芯位居国内人工智能芯片第一梯队;核心技术及算法层方面,获备案大模型企业94款,百度文心一言等已成为面向公众服务的明星产品;应用层方面,衔远科技、第四范式等已在传统产业赋能、金融、政务等领域实现示范应用。 询问AI
- 下一篇
从ORM到OQM之3:查询对象和动态查询映射
1. 引言 在对使用if语句构建动态查询的代码进行重构后,我们实现了一种可以通过查询对象的实例直接构建动态查询的方法。这种方法包括以下步骤: 遍历查询对象的所有字段; 通过反射获取字段的赋值,根据已赋值字段的注解得到对应的查询条件,并将字段的赋值添加到参数列表。 使用AND将多个查询条件组合成查询子句。 借助这种方法,每新增一个查询条件,只需在查询对象中添加一个字段和声明了SQL条件的注解即可。 并且由于其通用性,构建动态查询的实现方法可以放在单独的仓库中进行维护和发布。 然而,随着查询条件的类型和数量的增加,通过注解声明查询条件的弊端也逐渐显现,主要存在以下问题: 查询条件中的列名和字段名称存在重复; IN操作符的变长占位符需要特殊处理; 需要使用OR运算符连接多个查询条件; 需要支持子查询。 通过分析,我们发现操作符为等号的查询条件可以直接从字段名映射而得,从而避免在注解中重复编写SQL条件。这也让我们发现了消除SQL注解这个优化方向。 2. 查询条件归类 基于查询条件的特性,我们将其分为以下四类,每类查询条件由一种类型的字段映射得到: 包含列名、运算符和参数的基础查询条件 使用A...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- MySQL8.0.19开启GTID主从同步CentOS8
- Mario游戏-低调大师作品
- Linux系统CentOS6、CentOS7手动修改IP地址
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7安装Docker,走上虚拟化容器引擎之路
- Docker快速安装Oracle11G,搭建oracle11g学习环境