1.为什么要使用泛型(generic)程序设计?

在《Java核心技术》中的阐述:编写的代码可以被许多不同类型的对象所重用,这样就允许泛型代码和遗留代码之间能够相互操作。

提到的两个概念:类型参数通配符类型

在《Head first Java》中的解释似乎更通俗易懂些:几乎所有以泛型编写的程序都与处理集合有关,虽然泛型可以用在其他地方,但它主要目的还是让你能够写成有类型安全性的集合,也就是说编译器能够帮忙防止你把Dog加到一群Cat中。

就像在Collection类的sort方法中有写明:public static <T extends Comparable<?super T>>void sort (List<T> list)其中Comparable<?super T>就是在对参数类型做限制,加入的是什么对象,返回的还是该对象的引用。

在泛型功能出现前,编译器无法注意到你加入集合中的东西是什么,因为所有的集合都写成处理Object类型,可以把任何东西放进ArrayList中,有点像ArrayList<Object>

在Java的程序或文件中只要用到<>这组符号, 就表示泛型正在作用—它是一种从Java 5.0开始加入的特质。

ArrayList虽然是最常用的,但偶尔还是会有特殊情况,比如ArrayList没有排序方法。下面列出几个重要的:

LinkedList:针对经常插入或删除中间元素所设计的高效率集合(实际上ArrayList还是比较实用)

TreeSet:以有序状态保持并防止重复

(TreeSet的元素必须是Comparable

使用TreeSet,下列其中一项必须为真

集合中的元素必须是有实现Comparable的类型

使用重载,取用Comparator参数的构造函数来创建TreeSet

HashSet:防止重复的集合,可快速地找到相符的元素。(但是要override hashcode()和equals()这两个方法)

HashMap:可用成对的name/value来保存于取出

LinkedHashMap:类似HashMap,但是可记住元素插入的顺序,也可以设定成按照元素上次存取的先后来排序。

 

关于泛型

1)         创建被泛型化类(例如ArrayList)的实例

创建ArrayList时你必须要指定它所容许的对象,就像单纯的数组那样。

new ArrayList<Song>()

2)         声明与指定泛型类型的变量

多态遇到泛型类型会怎么样?

数组与ArrayList

对于ArrayList,如果把方法声明成取用ArrayList<Animal>,它就智慧取用ArrayList< Animal >参数,ArrayList< Animal的子类>就行,而数组就可以实现。

数组的类型是在运行期间检查的,但集合的类型检查只会发生在编译期间,所以如果出现类型错误,对于集合来说,编译是都无法通过的。

泛型与多态

万用字符?:用来接受Animal子型参数的方法

public void takeAnimals (ArrayList<? extends Animal> animals){   ……

}

extends同时代表继承和实现

java 泛型集合上机题 java泛型与集合_类型变量

java 泛型集合上机题 java泛型与集合_Java_02

List<Song> songlist=new ArrayList<Song>()

1)         声明(与调用)取用泛型类型的方法

声明:void foo(List<Song> list)

调用x.foo(songList)

总结:主要就是泛型类,泛型变量,泛型方法。

注:API的设计团队已经涵盖了大部分你会遇到的额数据结构,而几乎只有集合会真的需要泛型。

 

使用泛型的类

ArrayList是最常用的泛型化类型,我们从查看它的说明文件说起。

public class ArrayList<E> extends Abstraction<E> implements List<E>…{

……

}

其中E就被称为类型参数

运用泛型的方法

泛型的类代表类的声明用到类型参数,泛型的方法代表方法的声明特征用到类型参数

在方法中的类型参数有几种不同的运用方式:

1)         使用定义在类声明的类型参数

public class ArrayList<E> extends AbstracList<E>…{
public boolean add(E o)

2)         使用未定义在类声明的类型参数

public <T extends Animal> void takeThing(ArrayList<T> list)

代表传入Animal或其子型来出初始化ArrayList。

 

从Collection的API说明文件中我们发现3个主要的接口:List、Set和Map

LIST:对付顺序的好帮手

是一种知道索引位置的集合,List知道某物在系列集合中的位置,可以有多个元素引用相同的对象。

SET:注重独一无二的性质

不允许重复的集合。它知道某物是否已经存在于集合中,不会有多个元素引用相同的对象

MAP:用key来搜索的专家

使用成对的键值和数据值。Map会维护与key有关联的值,两个key可以引用相同的对象,但是key不能重复,典型的key是String,但也可以是任何对象。

 

集合的API

java 泛型集合上机题 java泛型与集合_类型变量_03

java 泛型集合上机题 java泛型与集合_类型变量_04

 

 

 

以上内容来自Head first Java,接下来的内容from 《Java核心技术》 (感觉该书阐述的有点抽象)

泛型程序设计分为3个能力级别:

1)      仅仅使用泛型类

2)      能够利用Java泛型系统地解决代码衔接,泛型类混合问题。

3)      实现自己的泛型类和泛型方法。

2.泛型类:具有一个或多个类型变量的类。

java 泛型集合上机题 java泛型与集合_泛型_05

pair类引入了一个类型变量T,用尖括号<>括起来,并放在类名后面。

泛型类可以有多个类型变量,例如,也可以这样定义pair类,其中第一个域和第二个域使用不同的类型:

public class Pair<T,U>{. . .}

3.泛型方法:

如下为定义一个带有类型参数的简单方法:

class ArrayAlg
{
         public static <T> T getMiddle(T. . .a)
                   {
                            return a[a.length/2];
                   }
}

类型变量放在修饰符public static的后面,返回类型的前面。

泛型方法可以定义在普通类中,也可以定义在泛型类中。

4.类型变量的限定

为类型变量实现接口,来达到限定的目的,避免产生编译错误,如,为T实现Comparable接口

public static <T extends Comparable> T getMiddle(T. . .a)

类型擦除:去掉类型变量的限制,或者将类型变量替换为object

桥方法:为解决类型擦除与多态发生冲突的问题

有关Java泛型转换的事实:

虚拟机没有泛型,只有普通的类和方法。

所有的参数类型都用它们的限定类型替换

桥方法被合成来保持多态

为保持类型安全性,必要时插入强制类型转换