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 ...
随机推荐
- Print all attributes and values in a Javascript Object
function printObject(o) { var out = ''; for (var p in o) { out += '\n' + ':: ' + p + '(' + typeof(o[ ...
- iframe中video没有全屏按钮
HTML内联框架元素 <iframe> iframe默认不允许全屏, 如果内嵌了video那么控制条上将不显示全屏按钮, 通过添加allowfullscreen属性可以开启全屏功能. mo ...
- CentOS7中设置Tomcat8开机自启动
CentOS7中设置Tomcat8开机自启动 本文介绍了在centos7中配置tomcat的开机自启动的一些操作步骤,仅供参考. 环境是CentOS 7 ,jdk版本是1.8.0_191,tomcat ...
- mysql基础SQL练习
许久收藏的练习mysql语句的,现在看来任然有学习价值! 表如下: Student(Sid,Sname,Sage,Ssex) 学生表 Course(Cid,Cname,Tid) 课程表 SC(Sid, ...
- 好用好玩的Python包
ujson 用C++实现的json解析器,速度飞快. prettytable 在控制台下使用表格展示数据 import prettytable t=prettytable.PrettyTable([' ...
- Effective Java 第三版——68. 遵守普遍接受的命名约定
Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...
- 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 ...
- Autohotkey window 下宏键盘、宏命令开发入门
- fastcgi php-cgi与php-fpm区别和之间的关系
关于FastCGI.php-cgi.php-fpm的区别是什么,各自有什么用途,以及相互间的关系是什么,查阅相关资料,可谓是众说纷纭,莫衷一是: 说法一:fastcgi是一个协议,php-fpm实现了 ...
- 使用JavaScript验证用户输入的是否为正整数
在项目开发中,需要使用JavaScript验证用户输入的是否为正整数. 方法一: var type="^[0-9]*[1-9][0-9]*$"; var r=new RegExp( ...