java泛型探索——介绍篇

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]):

1 List<String> words = new ArrayList<String>();
2 由于泛型的类型擦除特性,所有添加到words中的变量,都会被转换为Object,
3 此时就需要泛型的类型转换特性,在执行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

时间: 2024-10-07 19:08:41

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

第10篇-JAVA 集合框架-JAVA 泛型

第10篇-JAVA 集合框架-JAVA 泛型 每篇一句 :所有的不甘,都是因为还心存梦想 初学心得: 不是每件事都注定会成功,但是每件事都值得一试 (笔者:JEEP/711)[JAVA笔记 | 时间:2017-04-15| JAVA 集合框架/JAVA 泛型 ] 1.JAVA 集合框架概念 通俗的说,集合就是一个存放数据的容器,准确的说,就是放数据对象引用的容器 数组和集合都是容器,有何不同? 数组长度固定,集合长度可变 数组只能存放相同类型的数据,集合可以存放不同类型的数据 数组可存放简单数据

面向对象,Java泛型篇

一.Java泛型入门基础 1. 泛型历史:集合中可以存储任意类型对象,但是在取出时,如果要使用具体对象的特有方法时,需要进行向下转型,如果存储的对象类型不一致,在转型过程中就会出现ClassCastException异常.这样就给程序带来了不安全性. 在jdk1.5以后就有了解决方案--泛型技术:在存储元素时,就不允许存储不同类型的元素.存储了就编译失败. 所以就需要在存储元素时,在容器上明确具体的元素类型,这其实和数组定义很像. 2.优势:1)将运行时期的ClassCastException异

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

现在开始深入学习java的泛型了,以前一直只是在集合中简单的使用泛型,根本就不明白泛型的原理和作用.泛型在java中,是一个十分重要的特性,所以要好好的研究下. 泛 型的定义:泛型是JDK 1.5的一项新特性,它的本质是参数化类型(Parameterized Type)的应用,也就是说所操作的数据类型被指定为一个参数,在用到的时候在指定具体的类型.这种参数类型可以用在类.接口和方法的创建中,分别称为泛 型类.泛型接口和泛型方法. 泛型思想早在C++语言的模板(Templates)中就开始生根发芽

《java.util.concurrent 包源码阅读》09 线程池系列之介绍篇

concurrent包中Executor接口的主要类的关系图如下: Executor接口非常单一,就是执行一个Runnable的命令. public interface Executor { void execute(Runnable command); } ExecutorService接口扩展了Executor接口,增加状态控制,执行多个任务返回Future. 关于状态控制的方法: // 发出关闭信号,不会等到现有任务执行完成再返回,但是现有任务还是会继续执行, // 可以调用awaitTe

java泛型的基本介绍和使用

现在开始深入学习java的泛型了,以前一直只是在集合中简单的使用泛型,根本就不明白泛型的原理和作用.泛型在java中,是一个十分重要的特性,所以要好好的研究下. 一.泛型的基本概念 泛型的定义:泛型是JDK 1.5的一项新特性,它的本质是参数化类型(Parameterized Type)的应用,也就是说所操作的数据类型被指定为一个参数,在用到的时候在指定具体的类型.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型接口和泛型方法. 泛型思想早在C++语言的模板(Templates)

java泛型介绍

一.泛型初衷 Java集合不会知道我们需要用它来保存什么类型的对象,所以他们把集合设计成能保存任何类型的对象,只要就具有很好的通用性.但这样做也带来两个问题: –集合对元素类型没有任何限制,这样可能引发一些问题:例如想创建一个只能保存Dog对象的集合,但程序也可以轻易地将Cat对象“丢”进去,所以可能引发异常. –由于把对象“丢进”集合时,集合丢失了对象的状态信息,集合只知道它盛装的是Object,因此取出集合元素后通常还需要进行强制类型转换.这种强制类型转换既会增加编程的复杂度.也可能引发Cl

java泛型介绍及实例

java泛型 什么是泛型? 泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样. 可以在集合框架(Collection framework)中看到泛型的动机.例如,Map 类允许您向一个 Map 添加任意类的对象,即使最常见的情况是在给定映射(map)中保存某个特定类型(比如 String)的对象. 因为 M

赢在面试之Java泛型篇(十二)

139. Java中的泛型是什么 ? 使用泛型的好处是什么? 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数. 好处: 1.类型安全,提供编译期间的类型检测 2.前后兼容 3.泛化代码,代码可以更多的重复利用 4.性能较高,用GJ(泛型JAVA)编写的代码可以为java编译器和虚拟机带来更多的类型信息,这些信息对java程序做进一步优化提供条件. 140,Java的泛型是如何工作的 ? 什么是类型擦除 ?如何工作? 1.类型检查:在生成字节

Java泛型简明教程

Java泛型简明教程 博客分类: Java综合 JavaApple数据结构CC++ Java泛型简明教程 本文是从 Java Generics Quick Tutorial 这篇文章翻译而来. 泛型是Java SE 5.0中引入的一项特征,自从这项语言特征出现多年来,我相信,几乎所有的Java程序员不仅听说过,而且使用过它.关于Java泛型的教程,免费的,不免费的,有很多.我遇到的最好的教材有: The Java Tutorial Java Generics and Collections ,