Java 泛型背后的原理是什么?
云栖号资讯:【点击查看更多行业资讯】
在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来!
这一节主要讲的内容是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类型,因此泛型擦除是对于虚拟机而言的。
下面我们再来看一种泛型结构:
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<>(); @Override public void addNode(Map<K, V> map) { DATAS.addLast(map); } @Override public Map<K, V> getNode(int index) { return DATAS.get(index); } }
通配符
<?>通配符和区别是在你不知道泛型类型的时候,可以用通配符来定义,下面通过一个例子来看看的用处:
//定义了一个普通类 public class BaseBean<T> { T value; public T getValue() { return value; } public void setValue(T value) { this.value = value; } } //用来定义泛型的 public class Common1 extends Common { }
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。
另外,关注微信公众号:互联网架构师,在后台回复:2T,可以获取架构师视频教程,都是干货。
通配符不能定义在类上面、接口或方法上,只能作用在方法的参数上
public void setClass(Class<?> class){ //todo }
、、<? extends>、<? super>
表示上限泛型、表示下限泛型
为了演示这两个通配符的作用,增加了一个类:
public void add(Class<? super Common> clazz) {}
可以看到当传进去的是Common1.class的时候是不合法的,因为在add方法中需要传入Common父类的字节码对象,而Common1是继承自Common,所以直接不合法。
在实际开发中其实知道什么时候定义什么类型的泛型就ok,在mvp实际案例中泛型用得比较广泛,大家可以根据实际项目来找找泛型的感觉,只是面试的时候需要理解类型擦除是针对谁而言的。关注微信公众号:互联网架构师,获取更多架构技术干货。
类型擦除
其实在开篇的时候已经通过例子说明了,通过反射绕开泛型的定义,也说明了类中定义的泛型最终是以Object被jvm执行。
所有的泛型在jvm中执行的时候,都是以Object对象存在的,加泛型只是为了一种代码的规范,避免了开发过程中再次强转。
泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。
【云栖号在线课堂】每天都有产品技术专家分享!
课程地址:https://yqh.aliyun.com/zhibo立即加入社群,与专家面对面,及时了解课程最新动态!
【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK
原文发布时间:2020-05-27
本文作者:的一幕
本文来自:“互联网架构师 微信公众号”,了解相关信息可以关注“互联网架构师”
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
物联网能源应用:从智能车辆到智能电表
云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 物联网正迅速使能源领域成为一个令人兴奋的领域。从智能计量到车辆到电网的解决方案,这些公用设施都准备好了重新改造。 物联网在虚拟现实、人工智能和工业流程中迎来了许多激动人心的发展。物联网包含许多创新,这些创新使我们感觉更强大,更有效并且可以更好地控制我们的现实。 以下是物联网在能源领域的两个应用,这些应用将改变我们衡量和节省能源的方式。 物联网能源应用 1.智能电表 传统上,电表会记录您在家中使用的电量,然后,您的电力供应商的一名员工会读取该电表读数并据此向您收费。 然而,使用智能能源,传统模拟仪表和智能仪表之间有一些不同: 1)模拟仪表需要员工阅读,而智能仪表则将您的能源消耗传输给公司,以便向您收费。 2)如果发生紧急情况,模拟仪表无法让您知道它们已经断电;而智能仪表会向公司发送通知,提醒它们断电。 3)模拟设备需要每年维护以确保准确性,而智能电表仅需要每10-20年更换一次电池。 智能水表也可以取代传统的水表。Costco是利用这一优势的公司之一,他与智能水务公司Apana合作,以更好...
- 下一篇
Spring Boot 2.3 中分层jar 是什么东西
背景 在我们实际生产容器化部署过程中,往往会遇到 Docker 镜像很大,部署发布很慢的情况 影响 docker 镜像大小的因素,主要有以下三个方面: 基础镜像的大小 。尽量选择 aphine 作为基础镜像 减少操作系统内置软件 Dockerfile 指令层数。 这就要求我们优化 Dockerfile 能合并在一行的尽量合并等 应用 jar 的大小。这是今天要分享的重点内容 helloworld 镜像 我们先来基于 spring boot 2.3.0 构建一个最简单的 web helloworld,然后构建镜像。 FROM adoptopenjdk:11-jre-hotspot as builder WORKDIR application ARG JAR_FILE=target/*.jar COPY ${JAR_FILE} application.jar ENTRYPOINT ["java", "-jar application.jar"] docker build --build-arg JAR_FILE=./demo-layer-0.0.1-SNAPSHOT.jar . -t de...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- CentOS8编译安装MySQL8.0.19
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS7安装Docker,走上虚拟化容器引擎之路
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- Mario游戏-低调大师作品
- 2048小游戏-低调大师作品
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作