目录
1 前言
面试阿里时,有一道编程题如下:
请编程实现冒泡排序的工具类,该方法支持对实现了Comparable接口的对象进行排序。
这道题就需要用到泛型的相关知识。虽然平时写代码经常使用Java集合,不可避免会用到泛型,但细想确实没有好好学习或者总结过泛型,于是就“蛋生”了这篇博客……
2 初识泛型
泛型(JDK5引入),字面意思是将类型泛化。在类、接口、方法定义的时侯,无需强制指定成员变量、输入参数或返回值的类型,由程序员在具体调用的时候来指定。好处有二:一是增加了代码的通用性,二是泛型可以提供编译时的类型安全检测。
2.1 提升代码通用性
我们在比较Java基础数据类型(如int、float、long)的大小时,可以使用“>”、“<”、“==”等运算符,然而当我们需要给String、Date或者自定义类型比较大小时,就需要使用另一套规则来衡量。
回到前言中的编程题,写一个冒泡排序并不难,整数版冒泡排序的Java代码如下。
public static void bubbleSort(int[] arr) {
boolean sortFlag = true;
// 长度为n的数组至多需要扫描n-1轮
// 若某一轮扫描结束发现sortFlag为false,则表示数组已经有序
for (int i = 0; sortFlag && i < arr.length - 1; i++) {
// 每一轮扫描先乐观地认为没有进行元素交换
sortFlag = false;
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
sortFlag = true;
}
}
}
}
问题来了,如果传入的是float类型怎么办?再重载一个?那如果还要对“学生”、“大炮”等自定义类排序怎么办?
public static void bubbleSort(float[] arr) {
// 省略……
}
public static void bubbleSort(Student[] arr) {
// 省略……
}
public static void bubbleSort(DaPao[] arr) {
// 省略……
}
请注意,题目要求是实现一个工具类,这样每次对新的类型进行冒泡排序都需要在工具类中重载新的方法是不能接受的!好在,题目也提示我们了只需要对实现的Comparable接口的对象进行排序。
下面来先看一下JDK中Comparable<T>接口的定义。
public interface Comparable<T> {
/**
* 将该对象与另一个指定对象进行比较排序
*
* @param o 被比较的对象
* @return 当该对象小于、等于、大于指定对象时分别返回负整数、零、正整数
*
* @throws NullPointerException 传入对象为null将抛出空指针异常
* @throws ClassCastException 若传入对象的类型不能与调用对象进行比较将抛出异常
*/
public int compareTo(T o);
}
这个compareTo方法就是用来替代“>”运算符的。因为我们并不知道用户传入的是什么类型的对象数组,那这个对象能不能用“>”来比较大小就更不知道了。为了保证排序方法的通用性,就可以使用compareTo来比较对象的大小了,具体比较的规则交给了该对象的实现类。是不是通用性极大地提高了,这才配将它放在工具类中。
// <T extends Comparable>