一、泛型的意义

泛型,又叫 显式参数多态,在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 中的泛型的更多相关文章

  1. Java中的泛型 (上) - 基本概念和原理

    本节我们主要来介绍泛型的基本概念和原理 后续章节我们会介绍各种容器类,容器类可以说是日常程序开发中天天用到的,没有容器类,难以想象能开发什么真正有用的程序.而容器类是基于泛型的,不理解泛型,我们就难以 ...

  2. [JavaCore]JAVA中的泛型

    JAVA中的泛型 [更新总结] 泛型就是定义在类里面的一个类型,这个类型在编写类的时候是不确定的,而在初始化对象时,必须确定该类型:这个类型可以在一个在里定义多个:在一旦使用某种类型,在类方法中,那么 ...

  3. Java 中的泛型详解-Java编程思想

    Java中的泛型参考了C++的模板,Java的界限是Java泛型的局限. 2.简单泛型 促成泛型出现最引人注目的一个原因就是为了创造容器类. 首先看一个只能持有单个对象的类,这个类可以明确指定其持有的 ...

  4. 【Java入门提高篇】Day14 Java中的泛型初探

    泛型是一个很有意思也很重要的概念,本篇将简单介绍Java中的泛型特性,主要从以下角度讲解: 1.什么是泛型. 2.如何使用泛型. 3.泛型的好处. 1.什么是泛型? 泛型,字面意思便是参数化类型,平时 ...

  5. Java开发知识之Java中的泛型

    Java开发知识之Java中的泛型 一丶简介什么是泛型. 泛型就是指泛指任何数据类型. 就是把数据类型用泛型替代了. 这样是可以的. 二丶Java中的泛型 Java中,所有类的父类都是Object类. ...

  6. Java中的泛型 --- Java 编程思想

    前言 ​ 我一直都认为泛型是程序语言设计中一个非常基础,重要的概念,Java 中的泛型到底是怎么样的,为什么会有泛型,泛型怎么发展出来的.通透理解泛型是学好基础里面中非常重要的.于是,我对<Ja ...

  7. 第九节:详细讲解Java中的泛型,多线程,网络编程

    前言 大家好,给大家带来详细讲解Java中的泛型,多线程,网络编程的概述,希望你们喜欢 泛型 泛型格式:ArrayList list= new ArrayList(); ArrayList list= ...

  8. Java基础之Java中的泛型

    1.为什么要使用泛型 这里我们俩看一段代码; List list = new ArrayList(); list.add("CSDN_SEU_Cavin"); list.add(1 ...

  9. java中的泛型2--注意的一些问题和面试题

    前言 这里总结一下泛型中需要注意的一些地方和面试题,通过面试题可以让你掌握的更清楚一些. 泛型相关问题 1.泛型类型引用传递问题 在Java中,像下面形式的引用传递是不允许的: ArrayList&l ...

随机推荐

  1. JSON序列——保存修改数据2

    JSON序列——保存修改数据2 procedure TForm1.Button7Click(Sender: TObject); begin var delta: TynJsonDelta := Tyn ...

  2. golang 无法将Slice类型[]a 转换为 Slice[]b

    因为我想做一个通用的Slice方法,AnySlice,但是将AnySlice定义为[]interface{ } 转换到别的类型,或者相互转换的时候都是会报错. 这是golang比较恶心人的一个地方了, ...

  3. 【技能意志矩阵-skill will matrix】工作中究竟是个人能力更重要,还是我们的积极性更能提高我们的业绩?

    工作中究竟是个人能力更重要,还是我们的积极性更能提高我们的业绩? 我们可以通过建立“个人能力(即技能)”和“积极性(即意志)”的矩阵(skill will matrix),找到自己的象限,并根据指导意 ...

  4. PL/SQL学习笔记之日期时间

    一:PL/SQL时间相关类型 PL/SQL提供两个和日期时间相关的数据类型: 日期时间(Datetime)数据类型 时间间隔类型 二:日期时间类型 datetime数据类型有: DATE TIMEST ...

  5. 初识go的tomb包

    在分析github.com/hpcloud/tail 这个包的源码的时候,发现这个包里用于了一个另外一个包,自己也没有用过,但是这个包在tail这个包里又起来非常大的作用 当时并没有完全弄明白这个包的 ...

  6. Android Studio系列-签名打包

    本篇博客纪录使用Android Studio对项目进行签名打包,跟Eclipse大同小异,读者朋友注意其中到差别. 第一步 创建签名文件 第二步 填写签名参数 第三步 选择构建类型 第四步 查看生成第 ...

  7. idea 配置普通web项目

    跟配置maven项目类似 idea 配置 maven 项目 注意点 1.取消第一步 2.添加依赖的时候,如果lib下没有servlet依赖包,可以加个tomcat环境进来编译 ps:在artifact ...

  8. What is a TensorFlow Session?

    Sep 26, 2016 I've seen a lot of confusion over the rules of tf.Graph and tf.Session in TensorFlow. I ...

  9. MySQL server has gone away

    场景: 批量写入数据时,MySQL server has gone away 解决方法: 在 my.ini 中 将 max_allowed_packet 参数设置大一点  show global va ...

  10. PowerDesigner 中模型设计导出Excel表格

    今天项目做设计,客户要看数据设计,需要到处Excel表格.去网上搜索下,把使用总结如下: 已经完成设计的pd设计 打开pd,快捷键Ctrl + Shift + X或者Tools>Exectue ...