点击上方蓝色“程序猿DD”,选择“设为星标”

回复“资源”获取独家整理的学习资料!

作者 | 的一幕

来源 | https://www.jianshu.com/p/dd34211f2565

这一节主要讲的内容是java中泛型的应用,通过该篇让大家更好地理解泛型,以及面试中经常说的泛型类型擦除是什么概念,今天就带着这几个问题一起看下:

举一个简单的例子:

这里可以看出来在代码编写阶段就已经报错了,不能往string类型的集合中添加int类型的数据。

那可不可以往List集合中添加多个类型的数据呢,答案是可以的,其实我们可以把list集合当成普通的类也是没问题的,那么就有下面的代码:

从这里可以看出来,不定义泛型也是可以往集合中添加数据的,所以说泛型只是一种类型的规范,在代码编写阶段起一种限制。

下面我们通过例子来介绍泛型背后数据是什么类型

public class BaseBean<T> {T value;public T getValue() {return value;}public void setValue(T value) {this.value = value;}
}

上面定义了一个泛型的类,然后我们通过反射获取属性和getValue方法返回的数据类型:

从日志上看到通过反射获取到的属性是Object类型的,在方法中返回的是string类型,因此咋们可以思考在getValue方法里面实际是做了个强转的动作,将object类型的value强转成string类型。

是的,没错,因为泛型只是为了约束我们规范代码,而对于编译完之后的class交给虚拟机后,对于虚拟机它是没有泛型的说法的,所有的泛型在它看来都是object类型,因此泛型擦除是对于虚拟机而言的。

下面我们再来看一种泛型结构:

这里我将泛型加了个关键字extends,对于泛型写得多的伙伴们来说,extends是约束了泛型是向下继承的,最后我们通过反射获取value的类型是String类型的,因此这里也不难看出,加extends关键字其实最终目的是约束泛型是属于哪一类的。所以我们在编写代码的时候如果没有向下兼容类型,会警告错误的:

大家有没有想过为啥要用泛型呢,既然说了泛型其实对于jvm来说都是Object类型的,那咱们直接将类型定义成Object不就是的了,这种做法是可以,但是在拿到Object类型值之后,自己还得强转,因此泛型减少了代码的强转工作,而将这些工作交给了虚拟机。

比如下面我们没有定义泛型的例子:

势必在getValue的时候代码有个强转的过程,因此在能用泛型的时候,尽量用泛型来写,而且我认为一个好的架构师,业务的抽取是离不开泛型的定义。

常见的泛型主要有作用在普通类上面,作用在抽象类、接口、静态或非静态方法上。

类上面的泛型

比如实际项目中,我们经常会遇到服务端返回的接口中都有errMsgstatus等公共返回信息,而变动的数据结构是data信息,因此我们可以抽取公共的BaseBean

public class BaseBean<T> {public String errMsg;public T data;public int status;
}

抽象类或接口上的泛型

//抽象类泛型
public abstract class BaseAdapter<T> {List<T> DATAS;}//接口泛型public interface Factory<T> {T create();
}
//方法泛型
public static <T> T getData() {return null;
}

多元泛型

public interface Base<K, V> {void setKey(K k);V getValue();}

泛型二级抽象类或接口

public interface BaseCommon<K extends Common1, V> extends Base<K, V> {
}//或抽象类
public abstract class BaseCommon<K extends Common1, V>
implements Base<K, V> {
}

抽象里面包含抽象

public interface Base<K, V> {//    void setKey(K k);    V getValue();void addNode(Map<K, V> map);Map<K, V> getNode(int index);}public abstract class BaseCommon<K, V> implements Base<K, V> {//多重泛型LinkedList<Map<K, V>> DATAS = new LinkedList<>();@Overridepublic void addNode(Map<K, V> map) {DATAS.addLast(map);}@Overridepublic Map<K, V> getNode(int index) {return DATAS.get(index);}
}

通配符  
<?>通配符<T>区别是在你不知道泛型类型的时候,可以用通配符来定义,下面通过一个例子来看看的用处:

//定义了一个普通类
public class BaseBean<T> {T value;public T getValue() {return value;}public void setValue(T value) {this.value = value;}
}//用来定义泛型的
public class Common1 extends Common {
}

在定义的时候将Common的泛型指向Common1的泛型,可以看到直接提示有问题,这里可以想,虽然Common1是继承自Common的,但是并不代表BaseBean之间是等量的。

在开篇也讲过,如果泛型传入的是什么类型,那么在BaseBean中的getValue返回的类型就是什么,因此可以想两个不同的泛型类肯定是不等价的,但是如果我这里写呢:

public static void main(String\[\] args) {BaseBean<Common> commonBaseBean = new BaseBean<>();//通配符定义就没有问题BaseBean<?> common1BaseBean = commonBaseBean;try {//通过反射猜测setValue的参数是Object类型的Method setValue = common1BaseBean.getClass().getDeclaredMethod("setValue", Object.class);setValue.invoke(common1BaseBean, "123");Object value = common1BaseBean.getValue();System.out.println("result:" + value);} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}
}

在上面如果定义的泛型是通配符是可以等价的,因为此时的setValue的参数是Object类型,所以能直接将上面定义的泛型赋给通配符的BaseBean。

另外,关注微信公众号:Java技术栈,在后台回复:Java,可以获取我整理的 N 篇 Java 教程,都是干货。

通配符不能定义在类上面、接口或方法上,只能作用在方法的参数上

其他的几种情况自己去尝试,正确的使用通配符:

public void setClass(Class<?> class){//todo
}

<T extends>、<T super>、<? extends>、<? super>
<T extends>表示上限泛型、<T super>表示下限泛型

为了演示这两个通配符的作用,增加了一个类:

//新增加的一个
BaseCommonpublic class Common extends BaseCommon{}

第二个定义的泛型是不合法的,因为BaseCommon是Common的父类,超出了Common的类型范围。10 道泛型面试题,推荐你看下。

不能作用在类、接口、方法上,只能通过方法传参来定义泛型  
在BaseBean里面定义了个方法:

public void add(Class<? super Common> clazz) {}

可以看到当传进去的是Common1.class的时候是不合法的,因为在add方法中需要传入Common父类的字节码对象,而Common1是继承自Common,所以直接不合法。

在实际开发中其实知道什么时候定义什么类型的泛型就ok,在mvp实际案例中泛型用得比较广泛,大家可以根据实际项目来找找泛型的感觉,只是面试的时候需要理解类型擦除是针对谁而言的。关注微信公众号:Java技术栈,获取更多Java技术干货。

类型擦除  
其实在开篇的时候已经通过例子说明了,通过反射绕开泛型的定义,也说明了类中定义的泛型最终是以Object被jvm执行。

所有的泛型在jvm中执行的时候,都是以Object对象存在的,加泛型只是为了一种代码的规范,避免了开发过程中再次强转。

泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。

往期推荐

如何用你最熟悉的 SQL 来查询 Elasticsearch 中的数据?

赠书|零压力入门算法的顶流畅销书《漫画算法》

Deno 1.0?我还没好好研究 Node,你就这样推倒重做?

RPC的超时设置,一不小心就是线上事故

17条避坑指南:一份来自谷歌的数据库经验贴

还在忍受限速网盘?来搭建一套自己的私有网盘!

欢迎加入我的知识星球,聊聊技术、说说职场、扯扯过去。头发很多的中年程序员DD在这里期待你的到来!加入方式:长按下方二维码噢

目前我已在星球中分享了如下四大板块内容,如果您对这些感兴趣,或是有相关困惑,欢迎加入与我们一起深入交流!

更多详细的精选内容点击阅读原文查看

面试:Java 泛型背后的原理是什么?相关推荐

  1. Java 泛型背后的原理是什么?

    这一节主要讲的内容是java中泛型的应用,通过该篇让大家更好地理解泛型,以及面试中经常说的泛型类型擦除是什么概念,今天就带着这几个问题一起看下: 举一个简单的例子: 这里可以看出来在代码编写阶段就已经 ...

  2. Java泛型背后是什么?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:的一幕 www.jianshu.com/p/dd34211f ...

  3. 什么是抽象类?抽象类的作用_揭秘!Java 泛型背后到底是什么?

    作者:的一幕 链接:www.jianshu.com/p/dd34211f2565 这一节主要讲的内容是java中泛型的应用,通过该篇让大家更好地理解泛型,以及面试中经常说的泛型类型擦除是什么概念,今天 ...

  4. 泛型类有什么作用_3 分钟带你彻底搞懂 Java 泛型背后的秘密

    优质文章,及时送达 作者 | 的一幕 来源 | www.jianshu.com/p/dd34211f2565 这一节主要讲的内容是java中泛型的应用,通过该篇让大家更好地理解泛型,以及面试中经常说的 ...

  5. Java泛型的实现原理

    由于前一段时间发现公司有些代码重复性很大,可以使用泛型方法简化,所以向领导提出,领导就让我整理了一下关于泛型的只是分享给大家. 一.Java泛型介绍 泛型是Java 1.5的新特性,泛型的本质是参数化 ...

  6. 封装设置属性,一家人都要整整齐齐系列(1) JAVA泛型的实现原理

    1.基本学过JAVA的人都知道一点泛型,明白常出现的位置和大概怎么使用.在类上为:class 类名<T> {} 在方法上为:public <T> void 方法名 (T x){ ...

  7. JAVA泛型的基本使用

    Java1.5版本号推出了泛型,尽管这层语法糖给开发者带来了代码复用性方面的提升,可是这只是是编译器所做的一层语法糖,在真正生成的字节码中,这类信息却被擦除了. 笔者发现非常多几年开发经验的程序猿,依 ...

  8. java泛型-类型擦除

    2019独角兽企业重金招聘Python工程师标准>>> 最近了解了一下java的泛型,了解到了"类型擦除"这个东西,现做个简单小结. java泛型实现的原理可以说 ...

  9. 什么是java泛型_java泛型背后是什么

    这一节主要讲的内容是java中泛型的应用,通过该篇让大家更好地理解泛型,以及面试中经常说的泛型类型擦除是什么概念,今天就带着这几个问题一起看下: 举一个简单的例子: image.png 这里可以看出来 ...

最新文章

  1. 基于机器视觉的智能人机交互技术
  2. LinkedList 源码分析
  3. 部署了OpenStack就拥有了云平台?还差很远呢
  4. 安装 oracle-xe,CentOS上安装Oracle XE指南
  5. python高并发架构_Python高并发和多线程有什么关系
  6. zabbix的安装(一)监控os资源:内存,cpu,io,负载,带宽
  7. docker 部署java_使用Java EE 7,WildFly和Docker进行持续部署–(第1部分)
  8. vector占用内存的释放
  9. 【Python】密码生成器
  10. jithub使用整理资料
  11. Linq 简介 及添加
  12. 矩池云上如何修改cudnn版本
  13. SuperMap iClient3D for WebGL 示范案例(一)倾斜模型加载
  14. word 公式编辑器 键入技巧 | 写数学作业必备速查表
  15. 最近很火的京东、天猫超市飞天茅台抢购是怎么回事,从原理流程给你们分析一波
  16. Google Guice简介
  17. 5分钟图解磁盘结构(软件层面)
  18. 一个有趣的模型组合预测模型
  19. Debian 9 Stretch国内常用镜像源 Jason-张百万
  20. Jena学习三——代码解释

热门文章

  1. Oracle ebs(E-Business Suite) 电子商务套件 简介
  2. linux c 判断路径是 目录还是文件
  3. linux 内核编译错误 .size expression for copy_user_generic_c does not evaluate to a constant
  4. python3 字典 dict 常见用法总结(判断key是否存在)
  5. 从零搭建前端脚手架工具
  6. linux shell crond crontab 定时器 计划任务 定时任务
  7. CentOS7使用systemctl添加自定义服务
  8. sqlmap tamper脚本编写
  9. C语言项目--教师信息/学生成绩管理系统
  10. 排序算法--排序算法汇总