Java 中的泛型
一、泛型的意义
泛型,又叫 显式参数多态,在c++里又叫模板。在强类型的编程语言中普遍作用是:
1. 可以显式地使用参数注入,实现代码复用(避免粗暴地使用 Object)
2. 加强编译时的类型安全(类型检查)
3. 减少类型转换的次数
二、Java 中的 泛型
编译时进行类型擦除生成与泛型类同名的原始类,但类型参数都被删去了。类型变量由类型限界代替(通常为 Object)。
三、集合协变与泛型上下界
Java 中泛型集合不具有协变性,无法利用多态替换参数。需要使用通配符,用于接收某些类型。 (PS: Java 中矩阵或者数组具有协变性,因此数组参数具有多态性。)
public static double totalArea(Collection<? extends Shape> arr)
四、泛型擦除
问题1: 什么时候需要避免泛型擦除?
使用泛型,程序在编译时,类型会完全擦除或保留部分(如果定义了上下限)。
涉及到具体类型的操作时会自动加上强制转换。比如:
public static void main(String[] args) {
List<Integer> m = new ArrayList<>();
m.add(3);
System.out.println(m.get(0) + 5);
}
编辑器会替换为:
public static void main(String[] args) {
List m = new ArrayList();
m.add(3);
System.out.println((Integer)m.get(0) + 5);
}
类型擦除还会造成以下编译时错误:
错误 ① “Erasure of method xyz(…) is the same as another method in type Abc”
public class App {
public int process(List<Person> people) {
for (Person person : people) {
log.info("Processing person: " + person.toString());
}
return person.size();
} public int process(List<Employee> employees) {
for (Employee employee : employees) {
log.info("Processing employee: " + employee.toString());
}
return employees.size();
}
}
以上代码由于类型擦除,会被编译成:
public class App {
public int process(List people) {
for (Person person : people) {
log.info("Processing person: " + person.toString());
}
return person.size();
}
public int process(List employees) {
for (Employee employee : employees) {
log.info("Processing employee: " + employee.toString());
}
return employees.size();
}
}
那么存在的错误显而易见。两个具有相同签名 ( process(List) ) 的方法无法在同一个类中共存,简单的解决方法是修改某一个方法的签名。
错误 ② “The method xyz(Foo) in the type Abc is not applicable for the arguments (Foo)”
public class App {
public int processPeople(List<Person> people){
for (Person person : people) {
log.info("Processing person: " + person.toString());
}
return person.size();
}
..
}
..
List<Employee>employees;
employees = new ArrayList<>();
employees.add(employee1);
employees.add(employee2);
App app = new App();
// ERROR ON NEXT LINE!
app.processPeople(employees);..
这个错误的原因是泛型集合不具有协变性。无法强制转换。
类型擦除有时还会影响序列化性能(因为不知道类型信息,从而无法针对性地选择序列化方式,因此影响了序列化的性能)。
问题2: 如何避免泛型擦除?
第一,使用泛型边界。可以有限地保留类型信息。如:
LinkedList<? extends Building>,LInkedList<? super House>
分别设置了上界和下界。在这种情况下编译器不会将泛型信息完全擦除,比如上述两个List经过编译后分别编程了LinkedList<Building> 和 LinkedList<House>。
第二,借助类型推断隐式确定具体参数类型,常用于函数式编程类型推断(需要编程语言支持)。
第三,不直接使用泛型。比如定义一个新的类型,继承或实现原泛型类或接口,并且注入具体的参数类型,则不会发生类型擦除。如:
env.fromElements(1, 2, 3)
.map(i -> new DoubleTuple(i, i))
.print(); public static class DoubleTuple extends Tuple2<Integer, Integer> {
public DoubleTuple(int f0, int f1) {
this.f0 = f0;
this.f1 = f1;
}
}
参考
https://www.ibm.com/developerworks/cn/java/java-language-type-erasure/index.html
Java 中的泛型的更多相关文章
- Java中的泛型 (上) - 基本概念和原理
本节我们主要来介绍泛型的基本概念和原理 后续章节我们会介绍各种容器类,容器类可以说是日常程序开发中天天用到的,没有容器类,难以想象能开发什么真正有用的程序.而容器类是基于泛型的,不理解泛型,我们就难以 ...
- [JavaCore]JAVA中的泛型
JAVA中的泛型 [更新总结] 泛型就是定义在类里面的一个类型,这个类型在编写类的时候是不确定的,而在初始化对象时,必须确定该类型:这个类型可以在一个在里定义多个:在一旦使用某种类型,在类方法中,那么 ...
- Java 中的泛型详解-Java编程思想
Java中的泛型参考了C++的模板,Java的界限是Java泛型的局限. 2.简单泛型 促成泛型出现最引人注目的一个原因就是为了创造容器类. 首先看一个只能持有单个对象的类,这个类可以明确指定其持有的 ...
- 【Java入门提高篇】Day14 Java中的泛型初探
泛型是一个很有意思也很重要的概念,本篇将简单介绍Java中的泛型特性,主要从以下角度讲解: 1.什么是泛型. 2.如何使用泛型. 3.泛型的好处. 1.什么是泛型? 泛型,字面意思便是参数化类型,平时 ...
- Java开发知识之Java中的泛型
Java开发知识之Java中的泛型 一丶简介什么是泛型. 泛型就是指泛指任何数据类型. 就是把数据类型用泛型替代了. 这样是可以的. 二丶Java中的泛型 Java中,所有类的父类都是Object类. ...
- Java中的泛型 --- Java 编程思想
前言 我一直都认为泛型是程序语言设计中一个非常基础,重要的概念,Java 中的泛型到底是怎么样的,为什么会有泛型,泛型怎么发展出来的.通透理解泛型是学好基础里面中非常重要的.于是,我对<Ja ...
- 第九节:详细讲解Java中的泛型,多线程,网络编程
前言 大家好,给大家带来详细讲解Java中的泛型,多线程,网络编程的概述,希望你们喜欢 泛型 泛型格式:ArrayList list= new ArrayList(); ArrayList list= ...
- Java基础之Java中的泛型
1.为什么要使用泛型 这里我们俩看一段代码; List list = new ArrayList(); list.add("CSDN_SEU_Cavin"); list.add(1 ...
- java中的泛型2--注意的一些问题和面试题
前言 这里总结一下泛型中需要注意的一些地方和面试题,通过面试题可以让你掌握的更清楚一些. 泛型相关问题 1.泛型类型引用传递问题 在Java中,像下面形式的引用传递是不允许的: ArrayList&l ...
随机推荐
- idea插件actiBPM源码
actiBPM https://github.com/Activiti/Activiti
- AsyncHttpSupport并发发送请求
public class AsyncHttpSupportTest { @InjectMocks private AsyncHttpSupport asyncHttpSupport; @Mock pr ...
- SSE图像算法优化系列二十:一种快速简单而又有效的低照度图像恢复算法。
又有很久没有动笔了,主要是最近没研究什么东西,而且现在主流的趋势都是研究深度学习去了,但自己没这方面的需求,同时也就很少有动力再去看传统算法,今天一个人在家,还是抽空分享一个简单的算法吧. 前段日子在 ...
- 分享12款令人瞠目结舌的WebVR演示和实验效果
不管你信不信, WebVR绝对是浏览器下一个让你激动的技术方向, 也许很快你就可以使用VR头显或者相关设备直接访问web内容和资源啦! 在这篇资源分享帖中,我们将介绍很多基于浏览器的VR演示和游戏,帮 ...
- Object 标签遮挡 Div 显示
最近在使用 Object 时,就是播放视频的 Object 标签遮挡住其他 div 标签,不能正常显示. 出现这种现象的原因: object 标签不在 dom 文档流里面,浏览器在解析的时候先把 ob ...
- BI 系列随笔列表 (SSIS, SSRS, SSAS, MDX, SQL Server)
微软 BI ETL 架构设计 如何在 ETL 项目中统一管理上百个 SSIS 包的日志和包配置框架 如何管理和记录 SSIS 各个 Task 的开始执行时间和结束时间以及 Task 中添加|删除|修改 ...
- 【大话QT之十二】基于CTK Plugin Framework的插件版本号动态升级
应用需求: 某些场景下我们可能面临这种问题,在执行着的应用程序不能终止的情况下,升级某个功能(或添,或减.或改动).在不採用CTK Plugin Framework插件系统架构的情况下这将是非常困难的 ...
- oracle 在已有表新增列内批量加数据
创建每列随机值的语句 create table TEST_ZHAA01A_03 as select rownum as id, to_char(sysdate + rownum/24/3600, 'y ...
- linux驱动面试题整理
1.字符型驱动设备你是怎么创建设备文件的,就是/dev/下面的设备文件,供上层应用程序打开使用的文件? 答:mknod命令结合设备的主设备号和次设备号,可创建一个设备文件. 评:这只是其中一种方式,也 ...
- Implementation of Message Receiver