Java泛型一览笔录

Wesley13
• 阅读 540

1、什么是泛型?

泛型(Generics )是把类型参数化,运用于类、接口、方法中,可以通过执行泛型类型调用 分配一个类型,将用分配的具体类型替换泛型类型。然后,所分配的类型将用于限制容器内使用的值,这样就无需进行类型转换,还可以在编译时提供更强的类型检查。

2、泛型有什么用?

泛型主要有两个好处:

(1)消除显示的强制类型转换,提高代码复用

(2)提供更强的类型检查,避免运行时的ClassCastException

3、泛型的使用

类型参数(又称类型变量)用作占位符,指示在运行时为类分配类型。根据需要,可能有一个或多个类型参数,并且可以用于整个类。根据惯例,类型参数是单个大写字母,该字母用于指示所定义的参数类型。下面列出每个用例的标准类型参数:

E:元素
K:键
N:数字
T:类型
V:值
S、U、V 等:多参数情况中的第 2、3、4 个类型
?  表示不确定的java类型(无限制通配符类型)

4、有界泛型

:是指 “ 上界通配符 (Upper Bounds Wildcards) ” :是指 “ 下界通配符 (Lower Bounds Wildcards) ” **\---这里有个坑** 举个例子,如下,注释的部分是编译不通过的。 /** * @author Sven Augustus */ public class Test { static class Species{} static class Human extends Species{} static class Man extends Human{} static class Woman extends Human{} public static void main(String[] args) { List list = new ArrayList(); list.add(new Man()); list.add(new Woman()); // Man o11 = (Man) list.get(0); // 这不能保证转型成功,也不是泛型的初衷 Human o12 = list.get(0); List list2 = new ArrayList(); // list2.add(new Object()); // 编译错误:这不能写入元素,类型校验失败 // list2.add(new Species()); // 编译错误:这不能写入元素,类型校验失败 // list2.add(new Human()); // 编译错误:这不能写入元素,类型校验失败 // list2.add(new Man()); // 编译错误:这不能写入元素,类型校验失败 // list2.add(new Woman()); // 编译错误:这不能写入元素,类型校验失败 // Man o21 = (Man) list2.get(0);// 这不能保证转型成功,也不是泛型的初衷 Human o22 = list2.get(0); List list3 = new ArrayList(); // list3.add(new Object()); // 编译错误:这不能写入元素,类型校验失败 // list3.add(new Species()); // 编译错误:这不能写入元素,类型校验失败 list3.add(new Human()); list3.add(new Man()); list3.add(new Woman()); // Man o31 = (Man) list3.get(0); // 这不能保证转型成功,也不是泛型的初衷 // Human o32 = list3.get(0); // 编译错误:无法自动转型为 Number Object o33 = list3.get(0); } } 那么我们看到 如 List 大家以为元素为 T以及其所有子类的对象 的List。其实不是。元素类型 仅指T的某一个不确定的子类,是单一的一个不确定类,没有具体哪个类。因此不能插入一个不确定的。 List 大家以为元素为 T以及其父类的对象 的List。其实不是,元素类型 仅指T的某一个不确定的父类,是单一的一个不确定类(只确定是T的父类),没有具体哪个类。 因此: 不能往List中插入任何类型的对象。唯一可以保证的是,你可以从中读取到T或者T的子类。 可以往List中插入T或者T子类的对象,但不可以插入T父类的对象。可以读取到Object或者Object子类的对象(你并不知道具体的子类是什么)。 **我们总结一下:** > **如果频繁支持读取数据,不要求写数据,使用。即生产者 使用 ** > > **如果频繁支持写入数据,不特别要求读数据,使用。即消费者 使用 ** > > **如果都需要支持,使用。** 5、类型擦除 ====== Java的泛型在编译期间,所有的泛型信息都会被擦除掉。 Class c1 = new ArrayList().getClass(); Class c2 = new ArrayList().getClass(); System.out.println(c1 == c2); > 这就是 Java 泛型的类型擦除造成的,因为不管是 ArrayList 还是 ArrayList,在编译时都会被编译器擦除成了 ArrayList。Java 之所以要避免在创建泛型实例时而创建新的类,从而避免运行时的过度消耗。 6、泛型类型信息 ======== 那么,如果我们确实某些场景,如HTTP或RPC或jackson需要获取泛型进行序列化反序列化的时候,需要获取泛型类型信息。 可以参照如下: package io.flysium.standard.generic; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; /** * 获取运行时的泛型类型信息 * * @author Sven Augustus */ public class Test2 { static class ParameterizedTypeReference { protected final Type type; public ParameterizedTypeReference() { Type superClass = this.getClass().getGenericSuperclass(); //if (superClass instanceof Class) { // throw new IllegalArgumentException( //"Internal error: TypeReference constructed without actual type information"); // } else { this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0]; //} } public Type getType() { return type; } } public static void main(String[] args) { // System.out.println(new ParameterizedTypeReference().getType()); // java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType // 此处会输出报错,因此ParameterizedTypeReference 应不能直接实例化,可以考虑加abstract System.out.println(new ParameterizedTypeReference() { }.getType()); // ParameterizedTypeReference 的匿名内部类,可以触发super(), //即 ParameterizedTypeReference()的构造器逻辑,正常运行 } } 注意一个关键点: 可以通过定义类的方式(通常为匿名内部类,因为我们创建这个类只是为了获得泛型信息)在运行时获得泛型参数。
点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
2年前
java 泛型详解
对java的泛型特性的了解仅限于表面的浅浅一层,直到在学习设计模式时发现有不了解的用法,才想起详细的记录一下。本文参考java泛型详解、Java中的泛型方法、java泛型详解1\.概述泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用。什么是泛型?为什么要使用泛型?泛型,即“参数化类型”。一提到参数,最熟
Wesley13 Wesley13
2年前
java泛型
一、实现机制java泛型实现方法为类型擦除,基于这种方法实现的泛型称为伪泛型。java泛型只在源代码中存在,在编译后的文件中替换为原生类型,并插入强制转换。(真正的泛型是应该存在于源码、编译后文件、运行期)二、擦除实例源码:List<StringtestListnewArrayList<String();
Stella981 Stella981
2年前
Gson通过借助TypeToken获取泛型参数的类型的方法
最近在使用Google的Gson包进行Json和Java对象之间的转化,对于包含泛型的类的序列化和反序列化Gson也提供了很好的支持,感觉有点意思,就花时间研究了一下。由于Java泛型的实现机制,使用了泛型的代码在运行期间相关的泛型参数的类型会被擦除,我们无法在运行期间获知泛型参数的具体类型(所有的泛型类型在运行时都是Object类型)。但是有的时候
Wesley13 Wesley13
2年前
Java泛型详解
引言Java泛型是jdk1.5中引入的一个新特性,泛型提供了编译时的类型检测机制,该机制允许程序员在编译时检测到非法的类型。泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用。本文我们将从零开始来看一下Java泛型的设计,将会涉及到通配符处理,以及让人苦恼的类型擦除。泛型基础
Wesley13 Wesley13
2年前
Java泛型的使用
泛型的定义:泛型,就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时(例如,继承或实现这个接口,用这个类型声明变量、创建对象时)确定(即传入实际的类型参数,也称为类型实参)。泛型的引入背景:集合容器类在设计阶段或声明阶段不能确定这个容器到底实际存储的是什么类型的对象
Easter79 Easter79
2年前
Thinking in java Chapter15 泛型
1与C比较2简单泛型泛型类3泛型接口4泛型方法5匿名内部类6构建复杂模型78910“泛型”意思就是:适用于许多许多的类型<h2id"1"1与C比较</h2C
Wesley13 Wesley13
2年前
Java的泛型详解(一)
Java的泛型详解(一)编写的代码可以被不同类型的对象所重用。因为上面的一个优点,泛型也可以减少代码的编写。1|2泛型的使用简单泛型类publicclassPair{privateTfirst;privateTsecond;publicPair(){firstnull;secondnull;
Stella981 Stella981
2年前
20175209 《Java程序设计》第八周学习总结
20175209《Java程序设计》第八周学习总结一、教材知识点总结1.泛型1.泛型类声明:格式classPeople<EPeople是泛型类名称E是泛型列表,可以是任何对象或接口,但不能是基本类型数据
Wesley13 Wesley13
2年前
JAVA 泛型中的通配符 T,E,K,V 傻傻分不清楚 ?
前言Java泛型(generics)是JDK5中引入的一个新特性,泛型提供了编译时类型安全检测机制,该机制允许开发者在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。泛型带来的好处在没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带
可莉 可莉
2年前
20175209 《Java程序设计》第八周学习总结
20175209《Java程序设计》第八周学习总结一、教材知识点总结1.泛型1.泛型类声明:格式classPeople<EPeople是泛型类名称E是泛型列表,可以是任何对象或接口,但不能是基本类型数据