概述

在JDK 5.0,Java语言引入了好几个新的功能,其中很重要的一个就是泛型(generics)。

本文就是对泛型的一个概述。你可以很熟悉其他语言中的类似结构,比如C++里的模板(templates)。如果这样,你将会看到两者之间有相似,同时也有很大的不同。如果你之前并不熟悉酷似的东西,那就更好了,你将会没有包袱,从而重头开始。

泛型(generics)是一种对类型(types)的抽象。最常见的例子便是容量类型,比如 Java提供的Collections。

下面是Java中典型的排序用法。

List myIntList = new LinkedList(); // 1
myIntList.add(new Integer(0)); // 2
Integer x = (Integer) myIntList.iterator().next(); // 3

第三行的强制类型转换是比较烦人的。通常,程序员都是知道List里是放的什么类型的数据,然后,强制类型转换却是必不可少的。编译器只能仅仅保证Object对象被迭代器返回(iterator)。为了Integer变量赋值操作的类型安全,强制类型转换是必须的。

当然,强制类型转换并不仅仅带来混乱,还有可能因为程序员的失误,带来运行时的错误(run time error)。

能不能有种机制,程序员能明确表达意图,使一个List仅仅只能包含一个指明的类型?那这便是泛型(generics)的核心思想。下面是上面那份代码的泛型版本。

List<Integer> myIntList = new LinkedList<Integer>(); // 1'
myIntList.add(new Integer(0)); // 2'
Integer x = myIntList.iterator().next(); // 3'

留意下变量myIntList的声明,它并不只是个List,而是一个被写作List<Integer>的Integer List。我们叫List是一个泛型接口(generic interface),拥有一个type参数,Integer。当我们新建一个List对象的时候,需要特别指定一个type参数。同时,我们可以看到,第三行的强制类型转换也消失了。

现在,你也行会认为我们已经将杂乱的麻烦移除了。我们用第一行的类型参数Integer替换了第三行的Integer强制类型转换。然而,这两者却又很大的不同。编译器现在可以在编译期进行类型安全检测了。当我们用List<Integer>类型定义myIntList时,便告诉了编译器一些约定,同时,编译器会保证这些。在一些大型程序里,泛型提供了更好的健壮性。

以上内容翻译 Java 官网 Generics Introduction

简单定义

下面是Jdk中java.util包内,List和Iterator的定义的一些简单择录。

public interface List <E> {void add(E x);Iterator<E> iterator();
}public interface Iterator<E> {E next();boolean hasNext();
}

这些代码都是相似的,除了尖括号里的内容。尖括号里的内容其实就是List和Iterator的类型参数。

类型参数会用在泛型声明中所有需要真实类型地方(虽然有很多限制)。

在概述中,我们已经看到了泛型List的调用方法;在这个调用中,所有出现类型参数(通常也被叫做参数化的类型(parameterized type))的地方(在上面例子中的E)都会被真实类型替换(在上面例子中的Integer)。

你可能会想List<Integer>就是List的一个所有E都会Integer替换的特殊版本,像下面一样:

public interface IntegerList {void add(Integer x);Iterator<Integer> iterator();
}

这种类比,虽然有些好处,但它同时也是一种误导。

说这种类比有好处,是因为参数化类型的List<Integer>的确看起来像是这种扩展。
说它误导,是因为泛型重没有做这种替换扩展。泛型不是源代码的副本,也不是二进制的,不是硬盘上副本,也不是内存里的副本。如果你是个C++程序员,你就会发现这与C++模板非常不同。

一个泛型类型的源码仅仅只会被编译一次,被转成一个Class文件,就像普通类和接口一样。

类型参数在方法或构造函数里的使用方式和普通参数一样。就像函数参数声明表示值参数(formal value parameters),描述的是运行的值一样,一个泛型声明表示一个类型参数(formal type parameters)。当一个方法被调用时,实际参数会取代形式参数,然后执行函数体。当一个泛型被调用时,这个实际类型会用来替换形式类型参数。

一些关于命名约定的注意事项。我们推荐使用简短的方式(如果可以使用单字母)。最好能避免使用小写字母,从而很方便和普通类和接口名称区分。像上面的例子一样,很多集合类型都用E代表元素。后面我们还会有更多的例子。

以上内容翻译自Defining Simple Generics

泛型和子类型(Generics and Subtyping)

让我们测试对泛型的理解。下面的代码片段是否合法呢?

List<String> ls = new ArrayList<String>(); // 1
List<Object> lo = ls; // 2 

第一行,毫无疑问是合法的。棘手的问题是第二行。这个也就是说:一个String 的list是否是一个Object的List。大部分的人可能脱口而出说,是的。

那我们继续看下面的这几行:

lo.add(new Object()); // 3
String s = ls.get(0); // 4: Attempts to assign an Object to a String!

上面的例子,我们将lo当成ls的别名。通过别名lo访问了String的list ls,然后随便插入了一个Object对象进去。结果ls就再也不能只保存String的对象了,当我们想从ls里取出一些东西的时候,我们肯定会大吃一惊。

Java的编译器会阻止上面的事情发生。上面的第二行会引起一个编译期错误。
一般而言,如果Foo是Bar的一个子类型(subtype,(subclass or subinterface)),然后G是一个泛型定义,这不会导致G<Foo>是G<Bar>的一个子类型。这个也是泛型学习里很困难的事情,因为它违背我们深信不疑的直觉。

我们不能假设容器都是不变的。我们的直觉总是让我们感觉这些东西都是一成不变的。举个栗子,如果交管局(the department of motor vehicles,DMV)拥有一个人口普查局(the census bureau)里机动车驾驶员户口信息的list,这其实挺合理的。我们可能会认为List<Driver> 是一个List<Person>(is-a),假设Driver是Person的子类。但事实,只是把驾驶员信息做了一份拷贝。否则,如果人口普查局(the census bureau)新增一个非驾驶员的人口信息,将会污染DMV里的记录。

为了应对这种情况,我们需要更灵活地看待泛型的类型。到目前为止,我们看到的规则都是相当严格的。

以上内容翻译自 Java 官网 Generics and Subtyping

Java基础学习——泛型(generics)学习一相关推荐

  1. Java基础之泛型简单讲解(通俗易懂)

    Java基础之泛型简单讲解(通俗易懂) 1. 前言 2. 简单例子对比理解 2.1 未使用泛型例子--ArrayList 2.2 使用泛型的例子 2.2.1 ArrayList 举例 2.2.2 Ha ...

  2. java基础之泛型(Generics)

    泛型,广泛存在于各种开源框架及容器集合类中,在我们阅读源码的过程中一定会碰到,作为java基础知识的一个重要模块,对泛型的理解和掌握有助于我们在之后的源码阅读中借鉴框架思想以及在项目开发中灵活应用泛型 ...

  3. java基础代码实例_java学习之web基础(3):Servlet 和 Request的登录处理实例

    在页面输入用户名和密码,进行权限判断. 登录成功跳转到SuccessServlet展示:登录成功!用户名,欢迎您: 登录失败跳转到FailServlet展示:登录失败,用户名或密码错误. 我们这里使用 ...

  4. 【Java入门】泛型的学习与应用

    简介 以Table为例,class Table<T>{ } <> 表示这就是一个泛型,a.b都是T型的. class Table<T>{public T a;pub ...

  5. 【JAVA基础】重新系统学习Java(五)案例一

    目录 Java基础知识案例 运算符 身高遗传 红茶绿茶 外卖 if语句 手机以旧换新 三数最小 本息计算 顾客优惠 个人所得税 switch语句 加减乘除 循环语句 猪年年份 输出长方形 输出三角形 ...

  6. 博学谷:Java基础知识精讲学习笔记——DAY2

    1. Date类 ​ 日期和日历类,用于操作日期相关信息. ​ 构造方法 Date() : 构造一个日期对象,当前系统时间,精确到毫秒. package cn.itcast.dateandcalend ...

  7. 博学谷:Java基础知识精讲学习笔记——DAY 1

    1.IDEA项目目录详情 2. IDEA基本配置 ​ ①设置字体:File->Settings->Editor->Font ​ ②设置配色方案:File->Settings-& ...

  8. 【JAVA基础】java基础之-泛型详解

    写在前面的话 脑子是个好东西,可惜的是一直没有搞懂脑子的内存删除机制是什么,所以啊,入行多年,零零散散的文章看了无数,却总是学习了很多也忘了很多. 痛定思痛的我决定从今天开始系统的梳理下知识架构,记录 ...

  9. 14. Java基础之泛型

    一. 泛型概念的提出(为什么需要泛型)? 首先,我们看下下面这段简短的代码: 1 public class GenericTest { 2 3 public static void main(Stri ...

最新文章

  1. Leangoo 6.2.6 版发布
  2. Activity启动流程详解
  3. pip install 另一个程序正在使用此文件,进程无法访问
  4. python画画-用python实现你的绘画梦想
  5. JSP中的pageEncoding和contentType属性(转)
  6. 求一个整数数组的最大元素,递归方法实现
  7. 前沿 | 使用Transformers进行端到端目标识别
  8. 便利蜂发布《白领早餐报告》:仅5成白领每天吃早餐
  9. java 两数之差_1_两数之和(java)
  10. 聊聊你们关心的视频号
  11. Magento url 问题
  12. 物业管理系统c语言,物业管理系统C语言程序实习.doc
  13. android adb interface驱动安装失败,ADB interface驱动安装失败解决方法
  14. 纯html+css写一个收款收据或者发票样式
  15. centos修改镜像源
  16. idea新建sourceFolder
  17. Right Backup(云端数据备份软件)v8.1官方版
  18. Java练手小游戏---黄金矿工
  19. win10服务器修改远程密码,技术员解惑win10系统远程桌面保存密码后无法修改的设置方法...
  20. 基于51单片机的万年历proteus仿真原理图方案设计

热门文章

  1. 09 协方差与相关系数
  2. 四川一度智信:电商网店自然流量提升技巧
  3. [android基础]《疯狂android讲义》重点整理(2)
  4. Conda安装本地package
  5. [GZOI2017]小z玩游戏
  6. python做什么最好_刚学 Python,想做点小东西,做什么东西比较好
  7. 首次发现!数据异构影响联邦学习模型,关键在于表征维度坍缩 | ICLR 2023
  8. 一个好用 的API 管理工具
  9. PHP在泥浆中作用,浅析PHP膨润土泥浆在钻孔灌注桩的实际应用
  10. 微信小程序轮播图实例