1. 泛型出现前后代码对比

先来看看泛型出现前,代码是这么写的:

List words = new ArrayList();
words.add("Hello ");
words.add("worlds!");
String s = (String) words.get(0) + (String) words.get(1);
System.out.println(s.equals("Hello worlds!"));

而泛型出现后无需做显式转换:

words.add("Hello ");
words.add("worlds!");
String s = words.get(0) + words.get(1);
System.out.println(s.equals("Hello worlds!"));

从本质上来说,以上代码编译为字节码后是一样的,对JVM而言没有区别。

2. 为什么有泛型?

 泛型是什么?  

泛型允许程序员编写代码时使用一些以后才指定的类型,允许在定义类和接口的时候使用类型参数,java泛型的参数只可以代表类,不能代表个别对象。

泛型的引入可以解决之前的集合类框架在使用过程中通常会出现的运行时刻类型错误[1]

interface Iterator<E> {
    public boolean hasNext();
    public E next();
    public void remove();
        ...
}

泛型方法也可以哦:

class List {
    public static<T> List<T> toList(T[] arr) {
        List<T> list = new ArrayList<T>();
        for (T elt : arr) list.add(elt);
        return list;
    }
}

为什么有泛型? 

 1) 泛型可以隐式地执行类型转换,并且永远不会失败(cast-iron guarantee[2]):

 List<String> words = new ArrayList<String>();
 由于泛型的类型擦除特性,所有添加到words中的变量,都会被转换为Object,
 此时就需要泛型的类型转换特性,在执行words.get(i)时做强制转换。

2) 泛型由于类型擦除特性(后面的章节介绍),如List<Integer>,List<String>,List<Number>编译成字节码是一样的,

而不是每一个都有一个版本,保持着简洁性。

3) 最后也是最后要的一点:泛型的兼容性,可兼容jdk1.4以前的版本。从JVM的角度看,由于泛型代码编译成字节码与jdk1.4

之前的代码无任何差别,因此可以很容易的修改jdk1.4写的函数库中的某一个函数,而无需修改整个函数库。

3. 泛型通配符

首先以一个示例讲解为什么需要泛型通配符,如果我们定义addAll方法如下所示:

interface Collection<E> {
...
    public boolean addAll(Collection<E> c);
...
}

/**
 **测试代码
**/
List<Number> nums = new ArrayList<Number>();
List<Integer> ints = Arrays.asList(1,2,3);
nums.addAll(ints); // 编译错误

如果我们想在List<Number>中添加List<Integer>怎么办呢?这是就需要使用通配符了。

interface Collection<E> {
...
    public boolean addAll(Collection<? extends E> c);
...
}

/**
 **测试代码
**/
List<Number> nums = new ArrayList<Number>();
List<Integer> ints = Arrays.asList(1,2,3);
List<Double> dbls = Arrays.aslist(3.14,3.21);
nums.addAll(ints);
nums.addAll(dbls);

从上述代码可以看出,通配符的出现解决了泛型的子类问题:

List<Integer>与List<Double>都是List<? extends Number>的子类;而不是  List<Number>的子类。

最后,给出一个结论:当S是T的子类时,List<S>是List<?extends T>的子类;

当S是T的超类时,List<S>是List<? super T>的子类。此外,List<?>是List<? extends Object>的缩写。

接下来,我们分析通配符的重要的特性——put and get原则[2]

对extends而言,List<? extends T>只能get不能add或put。

List<Integer> ints = new ArrayList<Integer>();
ints.add(1);
ints.add(2);
List<? extends Number> nums = ints;
System.out.println(nums.get(0)); // 编译成功 nums.add(3); // 编译错误 nums.add(3.14); // 编译错误

对于super而言,List<? super T>只能put或add,不能get。

List<Number> ints = new ArrayList<Number>();
ints.add(1);
ints.add(2);
List<? super Integer> nums = ints;
nums.add(3); 

凡是都有例外,对于extends来说,List<? extends Number> nums可以add null,即nums.add(null);对于super来说,

List<? super Integer> nums  可以get(取出)Object对象。

4. 参考文献

[1]  http://www.infoq.com/cn/articles/cf-java-generics

[2] java Generics and Collections

java泛型探索——介绍篇的更多相关文章

  1. Java泛型学习---第二篇

    泛型学习第一篇 1.泛型之擦拭法 泛型是一种类似"模板代码"的技术,不同语言的泛型实现方式不一定相同. Java语言的泛型实现方式是擦拭法(Type Erasure). 所谓擦拭法 ...

  2. java泛型探索——小特性

    泛型特性(小篇幅) 1. 补充介绍一些常见的泛型特性: 类型参数T可以是recursive(类似递归性),它的边界可以是类型参数是自身的接口或类. 如我实现寻找最大值的方法,可以这么写: public ...

  3. Java泛型学习--第一篇

    还是那句话,学习某个知识一定要想想为什么要学它,这方面的知识用来解决什么问题的,怎么用,并且要总结的体系化,不能散的到处都是,方便以后查看博客. 今天参考廖雪峰老师官网学习并总结下泛型廖老师官网 1. ...

  4. java泛型探索——泛型类

    本文主要讨论一下如何声明泛型类,讨论的范围涉及构造函数.静态成员.内部类. 构造函数 泛型的类型参数首先声明在首部: public class Pair<T,U> { private fi ...

  5. Java——泛型

    前言 一般的类和方法,使用的都是具体的类型:基本类型或者自定义的类.如果我们要编写出适用于多种类型的通用代码,那么肯定就不能使用具体的类型.前面我们介绍过多态,多态算是一种泛化机制,但是也会拘泥于继承 ...

  6. 转!!java泛型

    介绍java泛型的一篇文章,通俗易懂! 原文地址:http://www.cnblogs.com/lwbqqyumidi/p/3837629.html 一. 泛型概念的提出(为什么需要泛型)? 首先,我 ...

  7. Java泛型介绍!!!

    Java总结篇系列:Java泛型  转自:http://www.cnblogs.com/lwbqqyumidi/p/3837629.html 一. 泛型概念的提出(为什么需要泛型)? 首先,我们看下下 ...

  8. Java 泛型 介绍

    为什么需要泛型? public class GenericTest { public static void main(String[] args) { List list = new ArrayLi ...

  9. java泛型(一)、泛型的基本介绍和使用

    现在开始深入学习java的泛型了,以前一直只是在集合中简单的使用泛型,根本就不明白泛型的原理和作用.泛型在java中,是一个十分重要的特性,所以要好好的研究下. 泛 型的定义:泛型是JDK 1.5的一 ...

随机推荐

  1. Unix环境编程基础下

    Unix出错处理 当UNIX系统的函数出错时,通常会返回一个负值.我们判断函数的返回值小于0表示出错了,注意我们并不知道为什么出错.例如我们open一个文件,返回值-1表示打开失败,但是为什么打开失败 ...

  2. js实现哈希表(HashTable)

    在算法中,尤其是有关数组的算法中,哈希表的使用可以很好的解决问题,所以这篇文章会记录一些有关js实现哈希表并给出解决实际问题的例子. 第一部分:相关知识点 属性的枚举: var person = { ...

  3. Java--JDBC连接数据库

         我们知道Java中的jdbc是用来连接应用程序和数据系统的,本篇文章主要就来看看关于JDBC的实现和使用细节.主要包含以下几点内容: JDBC的基本知识(数据驱动程序) JDBC的连接配置 ...

  4. JAVA加密算法系列-BASE64

    package ***; import java.io.IOException; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encode ...

  5. WPF自定义控件(1)——仪表盘设计[1]

    0.小叙闲言 又接手一个新的项目了,再来一次上位机开发.网上有很多控件库,做仪表盘(gauge)的也不少,功能也很强大,但是个人觉得库很臃肿,自己就计划动手来写一个控件库,一是为学习,二是为了项目.下 ...

  6. qt5的.ui文件在VS2010中无法编译问题

    自己手动添加的.ui文件在VS中是无法右键编译的,也即是说,在用QT designer编辑过的.ui文件无法实时更新相应的ui_XX.h文件,造成调试结果无法显示编辑过的新界面. 解决办法: 右键.u ...

  7. iTunes制作iPhone手机铃声方法(mac版2017年4月更新)

    iTunes制作iPhone手机铃声方法(mac版2017年4月更新)   跟之前百度出来的不同,我自己使用后写的.     1.首先下载好你需要制作铃声的mp3文件,这里我放在桌面.       2 ...

  8. C++实现的控制台-贪吃蛇

    周六终于可以抽出一整段时间了 想了想就写个贪吃蛇吧    第一次写 差不多下了140行  也不算太多吧 以后ACM比赛是在做不来就自己打个贪吃蛇玩 ps:本来想写个项目的 但是为了方便你们阅读 就写在 ...

  9. 配置WampServer以及搭建WordPress的一些问题,持续总结。

    这里用的版本是Wampserver2.4-x64. Wamp的安装就不赘述了,一路点通过就可以了. #注意:(最好别改,省的麻烦) 80端口是Apache 的默认端口,在httpd.conf文件中配置 ...

  10. CSS也需要重构

    最初接触到的CSS面向对象,是项目里的CSS超过8千行,缺乏约束和管理,在近期或不远的将来,有迫切的要求需要重构.CSS面向对象和模块化. CSS代码遇到的问题: 重用性差,看着一个CSS的名称,很难 ...