一、泛型的意义

泛型,又叫 显式参数多态,在c++里又叫模板。在强类型的编程语言中普遍作用是:

1. 可以显式地使用参数注入,实现代码复用(避免粗暴地使用 Object)

2. 加强编译时的类型安全(类型检查)

3. 减少类型转换的次数

二、Java 中的 泛型

编译时进行类型擦除生成与泛型类同名的原始类,但类型参数都被删去了。类型变量由类型限界代替(通常为 Object)。

三、集合协变与泛型上下界

Java 中泛型集合不具有协变性,无法利用多态替换参数。需要使用通配符,用于接收某些类型。 (PS: Java 中矩阵或者数组具有协变性,因此数组参数具有多态性。)

  1. public static double totalArea(Collection<? extends Shape> arr)

四、泛型擦除

问题1: 什么时候需要避免泛型擦除?

使用泛型,程序在编译时,类型会完全擦除或保留部分(如果定义了上下限)。

涉及到具体类型的操作时会自动加上强制转换。比如:

  1. public static void main(String[] args) {
  2. List<Integer> m = new ArrayList<>();
  3. m.add(3);
  4. System.out.println(m.get(0) + 5);
  5. }

编辑器会替换为:

  1. public static void main(String[] args) {
  2. List m = new ArrayList();
  3. m.add(3);
  4. System.out.println((Integer)m.get(0) + 5);
  5. }

类型擦除还会造成以下编译时错误:

错误 ① “Erasure of method xyz(…) is the same as another method in type Abc”

  1. public class App {
  2. public int process(List<Person> people) {
  3. for (Person person : people) {
  4. log.info("Processing person: " + person.toString());
  5. }
  6. return person.size();
  7. }
  8.  
  9. public int process(List<Employee> employees) {
  10. for (Employee employee : employees) {
  11. log.info("Processing employee: " + employee.toString());
  12. }
  13. return employees.size();
  14. }
  15. }

以上代码由于类型擦除,会被编译成:

  1. public class App {
  2. public int process(List people) {
  3. for (Person person : people) {
  4. log.info("Processing person: " + person.toString());
  5. }
  6. return person.size();
  7. }
  8. public int process(List employees) {
  9. for (Employee employee : employees) {
  10. log.info("Processing employee: " + employee.toString());
  11. }
  12. return employees.size();
  13. }
  14. }

那么存在的错误显而易见。两个具有相同签名 ( process(List) ) 的方法无法在同一个类中共存,简单的解决方法是修改某一个方法的签名。

错误 ② “The method xyz(Foo) in the type Abc is not applicable for the arguments (Foo)”

  1. public class App {
  2. public int processPeople(List<Person> people){
  3. for (Person person : people) {
  4. log.info("Processing person: " + person.toString());
  5. }
  6. return person.size();
  7. }
  8. ..
  9. }
  10. ..
  11. List<Employee>employees;
  12. employees = new ArrayList<>();
  13. employees.add(employee1);
  14. employees.add(employee2);
  15. App app = new App();
  16. // ERROR ON NEXT LINE!
  17. app.processPeople(employees);..

这个错误的原因是泛型集合不具有协变性。无法强制转换。

类型擦除有时还会影响序列化性能(因为不知道类型信息,从而无法针对性地选择序列化方式,因此影响了序列化的性能)。

问题2: 如何避免泛型擦除?

第一,使用泛型边界。可以有限地保留类型信息。如:

  1. LinkedList<? extends Building>,LInkedList<? super House>

分别设置了上界和下界。在这种情况下编译器不会将泛型信息完全擦除,比如上述两个List经过编译后分别编程了LinkedList<Building> 和 LinkedList<House>。

第二,借助类型推断隐式确定具体参数类型,常用于函数式编程类型推断(需要编程语言支持)。

第三,不直接使用泛型。比如定义一个新的类型,继承或实现原泛型类或接口,并且注入具体的参数类型,则不会发生类型擦除。如:

  1. env.fromElements(1, 2, 3)
  2. .map(i -> new DoubleTuple(i, i))
  3. .print();
  4.  
  5. public static class DoubleTuple extends Tuple2<Integer, Integer> {
  6. public DoubleTuple(int f0, int f1) {
  7. this.f0 = f0;
  8. this.f1 = f1;
  9. }
  10. }

参考


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. Print all attributes and values in a Javascript Object

    function printObject(o) { var out = ''; for (var p in o) { out += '\n' + ':: ' + p + '(' + typeof(o[ ...

  2. iframe中video没有全屏按钮

    HTML内联框架元素 <iframe> iframe默认不允许全屏, 如果内嵌了video那么控制条上将不显示全屏按钮, 通过添加allowfullscreen属性可以开启全屏功能. mo ...

  3. CentOS7中设置Tomcat8开机自启动

    CentOS7中设置Tomcat8开机自启动 本文介绍了在centos7中配置tomcat的开机自启动的一些操作步骤,仅供参考. 环境是CentOS 7 ,jdk版本是1.8.0_191,tomcat ...

  4. mysql基础SQL练习

    许久收藏的练习mysql语句的,现在看来任然有学习价值! 表如下: Student(Sid,Sname,Sage,Ssex) 学生表 Course(Cid,Cname,Tid) 课程表 SC(Sid, ...

  5. 好用好玩的Python包

    ujson 用C++实现的json解析器,速度飞快. prettytable 在控制台下使用表格展示数据 import prettytable t=prettytable.PrettyTable([' ...

  6. Effective Java 第三版——68. 遵守普遍接受的命名约定

    Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...

  7. JDBC告警系列(一)The server time zone value 'ÖÐ' is unrecognized or represents more than one time zone.

    一.现象 java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents ...

  8. Autohotkey window 下宏键盘、宏命令开发入门

  9. fastcgi php-cgi与php-fpm区别和之间的关系

    关于FastCGI.php-cgi.php-fpm的区别是什么,各自有什么用途,以及相互间的关系是什么,查阅相关资料,可谓是众说纷纭,莫衷一是: 说法一:fastcgi是一个协议,php-fpm实现了 ...

  10. 使用JavaScript验证用户输入的是否为正整数

    在项目开发中,需要使用JavaScript验证用户输入的是否为正整数. 方法一: var type="^[0-9]*[1-9][0-9]*$"; var r=new RegExp( ...