Head First Java 和 AcWing Java课程做的总结9。
9.1 引入
Java集合框架(Collection Framework
)能够支持绝大多数会用到的数据结构。
比如ArrayList<String>
,现在要对其排序,但ArrayList
没有sort()
这个方法。
ArrayList
不是唯一的集合:
TreeSet
HashMap
LinkedList
HashSet
LinkedHashMap
要排序现在可以用TreeSet
或者Collections.sort()
方法。
现在是可以用添加一行代码来排序
import java.util.*;
ArrayList<String> songList = new ArrayList<String>();
Collections.sort(songList);
但是现在要用Song
对象,而不是String
,则无法通过编译。
按理来视频,ArrayList
是一个List
,它实现了List
这个接口,应该没问题。但是编译器表示找不到ArrayList<Song>
参数的sort()
方法。
——>
那么ArrayList<Song>
和ArrayList<String>
的区别在哪?为什么不行?
查看sort()
函数的声明:
sort()
函数大量运用到了泛型(generic)功能- 注意符号
<>
,它代表着泛型正在作用。
9.2 泛型
几乎所有会以泛型写的程序都与处理集合有关,它的主要目的是让人写出有类型安全性的集合,它意味着更好的类型安全性。
泛型的重要性:
- 创建被泛型化类(如
ArrayList
)的实例。new ArrayList<Song>()
- 声明和指定泛型类型的变量。
List<Song> songList = new ArrayList<Song>
- 声明与调用泛型类型的方法。
void foo(List<Song> list);
x.foo(songList);
使用泛型的类:
ArrayList
是最常用的泛型化类型;它的类的声明如下:- 看上述代码中的
E
,会被编译器替换成实际的类型如String
; - 即
E
会被所指定的真正类型所取代,E
也被称为类型参数。
- 看上述代码中的
运用泛型的方法:
-
泛型的方法代表方法的声明特征会用到类型参数;
-
使用定义在类声明中的类型参数
-
public class Arraylist<E> extends AbstractList...{ public boolean add(E o) }
-
-
使用未定义在类声明的类型参数
-
public <T extends Animal> void takeThing(ArrayList<T> list){ //T可以是任何一种Animal }
-
如果类本身并没有使用类型参数,可以在方法的返回类型之前指定类型参数。
-
泛型与多态:
-
public <T extends Animal> void takeThing(ArrayList<T> list){ //T可以是任何一种Animal } public void takeThing(ArrayList<Animal> list){ }
-
两者都合法,但意义完全不同。
<T extends Animal>
是方法声明的一部分,表示任何被声明成Animal
或Animal
的子型的ArrayList
是合法的。因此可以用ArrayList<Dog>
、ArrayList<Cat>
或ArrayList<Animal>
来调用上面的方法。- 下面方法的参数是
ArrayList<Animal> list
,代表只有ArrayList<Animal>
是合法的。第二个方法只能使用Animal
的ArrayList
。
-
数组的类型是在运行期间检查的,但集合的类型检查只会在发生在编译期间。
9.3 sort()
的泛型详解
public static <T extends Comparable<? super T>> void sort(List<T> list)
根据上面的分析,可以看出sort()
方法只能接受Comparable
对象的的list
;
看String
的类声明:
- 看得出来,
Comparable
是个有泛型的接口,用的是关键字implements
问题:sort()
函数中使用extends
,而String
使用的implements
,怎么回事?
- 已泛型的观点,
extends
代表extends
或implements
- 它代表”是一个.....",且不管是接口或类都能适用。
所以想要对ArrayList<Song> songList
使用Collections.sort()
,必须要让Song
类实现Comparable
接口。
泛型的万用字符:
即?
上面存在一种sort()
方法的声明方式:
-
public static <T extends Comparable<? super T>> void sort(List<T> list)
-
在返回类型前声明类型参数。
还存在另外一种类型参数的声明方式:
-
public void takeThing(ArrayList<? extends Animal> list)
-
两者结果一样。
-
当参数存在多次
T
,则使用第一种更有效率。 -
在方法参数中使用万用字符时,编译器会阻止任何可以破坏引用参数所指集合的行为。
-
即可以调用
list
中任何参数,但不能加入元素; -
public void takeAnimal(ArrayList<? extends Animal> animals){ for(Animal a : animals){ a.eat(); }//这个可以 animals.add(new Cat());//这个不行,过不了编译 }
-
Comparable
接口:
-
public interface Comparable<T> { int compareTo(T o); }
-
java.lang.Comparable
-
只有
compareTo()
这一个方法,负值表示传入的大,正值表示正执行的大,0代表相等。 -
//实现举例 //Song类中title是String类型 public int compareTo(Song s){ return title.compareTo(s.getTitle()); }
Comparator
接口:
-
public interface Comparator<T> { int compare(T o1, T o2); }
-
java.util.Comparator
-
存在另一种
sort()
方法,它取用Comparator
参数。sort(List<T> list, Comparator<? super T> c)
-
使用
Comparable
接口,只能实现一种比较方式。但是可以做多个实现Comparator
的类,每种类实现一种比较方式