一、什么是泛型;

泛型的本质是 参数化类型,也就是说 将所操作的数据类型 指定为一个参数,在不创建新类的情况下,通过参数来指定所要操作的具体类型(类似于方法中的变量参数,此时类型也定义成参数形式),也就是说,在创建对象或者调用方法的时候才明确下具体的类型。可以在类、接口、方法中使用,分别称为泛型类、泛型接口、泛型方法。

二、泛型的好处:

没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。

而引入泛型后,有如下好处:

1、消除显式的强制类型转换,提高代码可读性:

泛型中,所有的类型转换都是自动和隐式的,不需要强制类型转换,可以提高代码的重用率,再加上明确的类型信息,代码的可读性也会更好。

2、编译时的类型检查,使程序更加健壮:

对于强制类型转换错误的情况,编译期不会提示错误,在运行的时候才出现异常,这是一个安全隐患。泛型的好处是在编译期检查类型安全,并能捕捉类型不匹配的错误,避免运行时抛出类型转化异常ClassCastException,将运行时错误提前到编译时错误,消除安全隐患。

三、Java类库中的泛型有那些?泛型的用途?

(1)泛型类:最常见的用途就是容器类,通过泛型可以完成对一组类的操作对外开放相同的接口。所有的标准集合接口都是泛型化的---Collection<V>、List<V>、Set<V> 和 Map<K,V>。

(2)泛型接口:类似地,集合接口的实现都是用相同类型参数泛型化的,所以HashMap<K,V> 实现 Map<K,V> 等都是泛型的,Comparable和Comparator接口也是泛型的。

除了集合类之外,Java 类库中还有几个其他的类也充当值的容器。这些类包括 WeakReference、SoftReference 和 ThreadLocal。

(3)泛型方法:要定义泛型方法,只需将泛型参数列表置于返回值之前。

静态方法上的泛型:静态方法无法访问类上定义的泛型。如果静态方法操作的引用数据类型不确定的时候,必须要将泛型定义在方法上。如下:

public static<Q> void function(Q t) {System.out.println("function:"+t);
}

四、泛型的上界下界:

<?extends T> 表示类型的上界,参数化类型可能是T 或者是 T的子类;

<? super T> 表示类型的下界,参数化类型是此T类型的超类型,直至object;

上界什么时候用:往集合中添加元素时,既可以添加T类型对象,又可以添加T的子类型对象。为什么?因为存的时候,T类型既可以接收T类对象,又可以接收T的子类型对象。

下界什么时候用:当从集合中获取元素进行操作的时候,可以用当前元素的类型接收,也可以用当前元素的父类型接收。

五、Java泛型的实现方法--类型擦除:

Java泛型的实现是靠类型擦除技术实现的,类型擦除是在编译期完成的,也就是在编译期,编译器会将泛型的类型参数都擦除成它指定的原始限定类型,如果没有指定的原始限定类型则擦除为object类型,之后在获取的时候再强制类型转换为对应的类型,因此生成的Java字节码中是不包含泛型中的类型信息的,即运行期间并没有泛型的任何信息。

下图参考博客:https://blog.csdn.net/shinecjj/article/details/52075499

(1)在使用泛型的时候,虽然传入了不同的泛型实参,但并没有真正意义上生成不同的类型,传入不同泛型实参的泛型类在内存中只有一个,即还是原来的最基本的类型;泛型只在编译阶段有效,在编译过程中,对于正确检验泛型结果后,会将泛型的相关信息擦除,并且在对象进入和离开方法的边界处添加类型检查和类型转化的方法,也就是说,成功编译后的class文件是不包含任何泛型信息的。总结成一句话:泛型类型在逻辑上看以看成是多个不同的类型,实际上都是相同类型。

(2)因此,泛型类型在逻辑上可以看成是多个不同的类型,但实际上都是相同的基本类型。类型参数在运行中并不存在,这意味着他们不会添加任何的时间和空间上的负担;但是,这也意味着不能依靠他们进行类型转换。

举两个例子说明一下类型擦除:

5.1、类型擦除:

public class Test4 {  public static void main(String[] args) {  ArrayList<String> arrayList1=new ArrayList<String>();  arrayList1.add("abc");  ArrayList<Integer> arrayList2=new ArrayList<Integer>();  arrayList2.add(123);  System.out.println(arrayList1.getClass()==arrayList2.getClass());  //true}  }  

在这个例子中,我们定义了两个ArrayList数组,不过一个是ArrayList<String>泛型类型,只能存储字符串。一个是ArrayList<Integer>泛型类型,只能存储整形。最后,我们通过arrayList1对象和arrayList2对象的getClass方法获取它们的类的信息,最后发现结果为true。说明泛型类型String和Integer都被擦除掉了,只剩下了原始类型。

5.2、转型和instanceof :

//泛型类被所有实例(instances)共享的另一个暗示是检查一个特定类型的泛型类是没有意义的。
Collection cs = new ArrayList<String>();
if (cs instanceof Collection<String>) { ...} // 非法类似的,如下的类型转换
Collection<String> cstr = (Collection<String>) cs;
得到一个unchecked warning,因为运行时环境不会为你作这样的检查。

六、类型擦除带来的问题:

详细参考这篇博客,博主介绍的很详细了:https://blog.csdn.net/LonelyRoamer/article/details/7868820

七、关于泛型的其他一些小细节:

1、可以创建泛型数组吗?相应的应用场景怎么处理?

不能创建泛型数组。一般的解决方案是任何想要创建泛型数组的地方都使用ArrayList?

2、可以将基本类型作为泛型参数吗?

泛型的类型参数只能是类类型(包括自定义类),不能是简单类型(基本数据类型)。

3、什么时候用泛型?

当接口、类及方法中的操作的引用数据类型不确定的时候,以前用的Object来进行扩展的,现在可以用泛型来表示。这样可以避免强转的麻烦,而且将运行问题转移到的编译时期。

4、泛型的细节:

(1)泛型实际代表什么类型,取决于调用者传入的类型,如果没传,默认是Object类型;

(2)使用带泛型的类创建对象时,等式两边指定的泛型类型必须一致。

原因:编译器检查对象调用方法时只看变量,然而程序在运行期间调用方法时就要考虑对象具体类型了。

(3)等式两边可以在任意一边使用泛型,在另一边不使用(考虑向后兼容);

ArrayList<String>al = new ArrayList<Object>();  //错
//要保证左右两边的泛型具体类型一致就可以了,这样不容易出错。
ArrayList<?extends Object> al = new ArrayList<String>();
al.add("aa");  //错
//因为集合具体对象中既可存储String,也可以存储Object的其他子类,所以添加具体的类型对象不合适,类型检查会出现安全问题。

推荐阅读:

https://juejin.cn/post/6911113640158593032

参考博客:

https://blog.csdn.net/s10461/article/details/53941091

https://blog.csdn.net/Jinuxwu/article/details/6771121

https://blog.csdn.net/caihuangshi/article/details/51278793

Java基础篇:泛型与类型擦除相关推荐

  1. java基础篇(11) 枚举类型

    枚举类型Enum的简介 1.什么是枚举类型 枚举类型: 就是由一组具有名的值的有限集合组成新的类型.(即新的类). 好像还是不懂,别急,咱们先来看一下 为什么要引入枚举类型 在没有引入枚举类型前,当我 ...

  2. 描述java泛型引入原则_Java/泛型的类型擦除/README.md · oslo/LearningNotes - Gitee.com

    前言 Java 泛型(Generic)的引入加强了参数类型的安全性,减少了类型的转换,但有一点需要注意:Java 的泛型在编译器有效,在运行期被删除,也就是说所有泛型参数类型在编译后都会被清除掉,看下 ...

  3. Java泛型:类型擦除

    前情回顾 Java泛型:泛型类.泛型接口和泛型方法 类型擦除 代码片段一 1 2 3 4 5 6 7 Class c1 = new ArrayList<Integer>().getClas ...

  4. java 泛型和类型擦除_关于Java泛型和擦除

    java 泛型和类型擦除 "编译期间擦除泛型"是常识(好吧,类型参数和实参实际上是被擦除的). 这是由于"类型擦除"而发生的. 但这是错误的,正如许多开发人员所 ...

  5. java object toarray_java从toArray返回Object[]到泛型的类型擦除

    在将ArrayList等Collection转为数组时,函数的返回值并不是泛型类型的数组,而是Object[].刚好最近翻了一遍<java核心技术>,以及参考<Think in Ja ...

  6. 《Java 后端面试经》Java 基础篇

    <Java 后端面试经>专栏文章索引: <Java 后端面试经>Java 基础篇 <Java 后端面试经>Java EE 篇 <Java 后端面试经>数 ...

  7. 高频面试真题答案 -java后端 -java基础篇

    原贴 2022届秋招高频面试真题汇总,千题奉送!!!- 后端篇_笔经面经_牛客网 整理答案: 类加载机制 47 双亲委派机制 24 new一个对象的过程 4 java程序是如何运行起来的? 1 jvm ...

  8. java基础篇---第一天

    今日开始在心中正式开始在培训班开始培训.一下是在培训的过程中发现自己在自学过的过程中发现的问题.这篇是java基础篇. 第一天 : 1)配置java环境变量 1.在系统变量中新建JAVA_HOME:j ...

  9. 大三Java后端暑期实习面经总结——Java基础篇

    博主现在大三在读,从三月开始找暑期实习,暑假准备去tx实习啦!总结下了很多面试真题,希望能帮助正在找工作的大家!相关参考都会标注原文链接,尊重原创! 目录 1. JDK.JRE.JVM的区别和联系 2 ...

  10. 14. Java基础之泛型

    一. 泛型概念的提出(为什么需要泛型)? 首先,我们看下下面这段简短的代码: 1 public class GenericTest { 2 3 public static void main(Stri ...

最新文章

  1. [ExtJS5学习笔记]第五节 使用fontawesome给你的extjs5应用添加字体图标
  2. 关键字之defer、panic、recover
  3. python 中的序列
  4. 观察者模式在SAP UI5主题更改功能中的应用
  5. 《C++ Primer》13.1.4节练习
  6. faker生成测试数据,一些数据生成方法摘取
  7. Scrapy框架学习(1)
  8. IE8升级到IE11 F12报错的解决方案
  9. 颜色的前世今生10·HSB拾色器详解
  10. S3C2410 通用异步收发UART 串口通信
  11. 安卓开发:记事本App
  12. 威海海燕计算机学校,与中成学校一起成长 ——高海燕
  13. Python将普通视频变成动漫视频,这就是知识的力量~
  14. 北工大电子与通信工程复试c语言,北京工业大学专硕考研复试经验
  15. 电脑连接linux系统怎么样,如今连Linux都弄不懂-当时我如果那么学习培训电脑操作系统就好啦...
  16. 豆芽的生长过程观察日记-绿豆发芽观察日记7天-2021年
  17. 15、Spark_RDD算子——AggregateByKey
  18. Redis-5-实际应用
  19. java计算机毕业设计家居门户网站MyBatis+系统+LW文档+源码+调试部署
  20. 直流电机,伺服电机和步进电机的区别

热门文章

  1. 七十二、Python | Leetcode字符串系列(下篇)
  2. Java web项目报错 Java compiler level does not match the version of the installed Java project facet.
  3. NeurIPS 2021 | 图上不均衡表示学习新视野:基于拓扑结构的不均衡学习
  4. 对比学习可以使用梯度累积吗?
  5. MLP回归,无需卷积、自注意力,纯多层感知机视觉架构媲美CNN、ViT
  6. A flight (to Boston) to Denver - 基于转移的顺滑技术研究 | 论文访谈间 #22
  7. render在python中的含义_python-/ render()上的Django TypeError获得了意外的...
  8. 在bcb中添加activex控件_LinkedCell 属性介绍,OLEObjects 控件
  9. mysql执行计划_mysql的sql执行计划详解
  10. python生成随机数代码_Python中产生随机数