考察目的:了解求职者对于Java基础知识的掌握程度。
考察范围:工作1-3年的Java程序员。
背景知识#
Java中的泛型,是JDK5引入的一个新特性。
它主要提供的是编译时期类型的安全检测机制。这个机制允许程序在编译时检测到非法的类型,从而进行错误提示。
这样做的好处,一方面是告诉开发者当前方法接收或返回的参数类型,另一方面是避免程序运行时的类型转换错误。
泛型的设计推演#
举一个比较简单的例子,首先我们来看一下ArrayList这个集合,部分代码定义如下。
publicclassArrayList{transientObject[] elementData;// non-private to simplify nested class access}
在ArrayList中,存储元素所使用的结构是一个Object[]对象数组。意味着可以存储任何类型的数据。
当我们使用这个ArrayList来做下面这个操作时。
publicclassArrayExample{publicstaticvoidmain(String[] args){ArrayList al=newArrayList();al.add("Hello World");al.add(1001);String str=(String)al.get(1);System.out.println(str);}}
运行程序后,会得到如下的执行结果
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Stringat org.example.cl06.ArrayExample.main(ArrayExample.java:11)
这种类型转换错误,相信大家在开发中有遇到过,总的来说,在没有泛型的情况下,会有两个比较严重的问题
需要对类型进行强制转换
使用不方便,容易出错
怎么解决上面这个问题呢?要解决这个问题,就得思考这个问题背后的需求是什么?
我简单总结两点:
要能支持不同类型的数据存储
还需要保证存储数据类型的统一性
基于这两个点不难发现,对于一个数据容器中要存储什么类型的数据,其实是由开发者自己决定的。因此,为了解决这个问题,在JDK5中就引入了泛型的机制。
其定义形式是:ArrayList<E>,它相当于给ArrayList提供了一个类型输入的模板E,E可以是任意类型的对象,它的定义方式如下。
publicclassArrayList{transientE[] elementData;// non-private to simplify nested class access}
在ArrayList这个类的定义中,使用<>语法,并传入一个用来表示任意类型的对象E,这个E可以随便定义,你可以定义成A、B、C都可以。
接着,把用来存储元素的数组elementData的类型,设置为E类型。
有了这个配置之后,ArrayList这个容器中,你想存储什么类型的数据,是由使用者自己决定,比如我希望ArrayList只存储String类型,那么它可以这么实现
publicclassArrayExample{publicstaticvoidmain(String[] args){ArrayList al=newArrayList();al.add("Hello World");al.add(1001);String str=(String)al.get(1);System.out.println(str);}}
在定义ArrayList时,传入一个String类型,这样写意味着后续往ArrayList这个实例对象al中添加元素,必须是String类型,否则会提示如下的语法错误。
同理,如果需要保存其他类型的数据,可以这么写:
ArrayList
ArrayList
总结:所谓泛型定义,其实本质上就是一种类型模板,在实际开发中,我们把一个容器或者一个对象中需要保存的属性的类型,通过模板定义的方式,给到调用者来决定,从而保证了类型的安全性。
泛型的定义#
泛型定义可以从两个维度来说明:
泛型类
泛型方法
泛型类#
泛型类指的是在类名后面添加一个或多个类型参数,一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。
类型变量的表示标记,常用的是:E(element),T(type)、K(key),V(value),N(number)等,这只是一个表示符号,可以是任何字符,没有强制要求。
下面的代码是关于泛型类的定义。
该类接收一个T标记符的类型参数,该类中有一个成员变量,使用T类型。
publicclassResponse{privateT data;publicTgetData(){returndata;}publicvoidsetData(T data){this.data = data;}}
使用方式如下:
publicstaticvoidmain(String[] args){Response res=newResponse<>();res.setData("Hello World");}
泛型方法#
泛型方法是指指定方法级别的类型参数,这个方法在调用时可以接收不同的参数类型,根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。
下面的代码表示泛型方法的定义,用到了JDK提供的反射机制,来生成动态代理类。
参考资料:
小海鲸 http://www.xiao-haijing.com
https://www.toutiao.com/item/7026966148713382404/
https://www.toutiao.com/item/7026963955188843044/
https://www.toutiao.com/item/7026962522527892004/
https://www.toutiao.com/item/7026961215020712486/
https://www.toutiao.com/item/7026960241069687328/
https://xiaohaijing.lofter.com/post/4d262a03_2b3ee9578
https://xiaohaijing.lofter.com/post/4d262a03_2b3edabc7
https://haokan.baidu.com/v?pd=bjh&vid=2773165931488765711
https://zhuanlan.zhihu.com/p/429767786
————————————————
版权声明:本文为CSDN博主「fenwei88」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/fenwei88/article/details/121162606