共计 2460 个字符,预计需要花费 7 分钟才能阅读完成。
使用 ArrayList
时,如果不定义泛型类型时,泛型类型实际上就是Object
:
// 编译器警告: | |
List list = new ArrayList(); | |
list.add("Hello"); | |
list.add("World"); | |
String first = (String) list.get(0); | |
String second = (String) list.get(1); |
此时,只能把 <T>
当作 Object
使用,没有发挥泛型的优势。
当我们定义泛型类型 <String>
后,List<T>
的泛型接口变为强类型List<String>
:
// 无编译器警告: | |
List<String> list = new ArrayList<String>(); | |
list.add("Hello"); | |
list.add("World"); | |
// 无强制转型: | |
String first = list.get(0); | |
String second = list.get(1); |
当我们定义泛型类型 <Number>
后,List<T>
的泛型接口变为强类型List<Number>
:
List<Number> list = new ArrayList<Number>(); | |
list.add(new Integer(123)); | |
list.add(new Double(12.34)); | |
Number first = list.get(0); | |
Number second = list.get(1); |
编译器如果能自动推断出泛型类型,就可以省略后面的泛型类型。例如,对于下面的代码:
List<Number> list = new ArrayList<Number>();
编译器看到泛型类型 List<Number>
就可以自动推断出后面的 ArrayList<T>
的泛型类型必须是ArrayList<Number>
,因此,可以把代码简写为:
// 可以省略后面的 Number,编译器可以自动推断泛型类型: | |
List<Number> list = new ArrayList<>(); |
泛型接口
除了 ArrayList<T>
使用了泛型,还可以在接口中使用泛型。例如,Arrays.sort(Object[])
可以对任意数组进行排序,但待排序的元素必须实现 Comparable<T>
这个泛型接口:
public interface Comparable<T> {/** | |
* 返回负数: 当前实例比参数 o 小 | |
* 返回 0: 当前实例与参数 o 相等 | |
* 返回正数: 当前实例比参数 o 大 | |
*/ | |
int compareTo(T o); | |
} |
可以直接对 String
数组进行排序:
// sort | |
import java.util.Arrays; | |
public class Main {public static void main(String[] args) {String[] ss = new String[] { "Orange", "Apple", "Pear" }; | |
Arrays.sort(ss); | |
System.out.println(Arrays.toString(ss)); | |
} | |
} |
这是因为 String
本身已经实现了 Comparable<String>
接口。如果换成我们自定义的 Person
类型试试:
// sort | |
import java.util.Arrays; | |
public class Main {public static void main(String[] args) {Person[] ps = new Person[] {new Person("Bob", 61), | |
new Person("Alice", 88), | |
new Person("Lily", 75), | |
}; | |
Arrays.sort(ps); | |
System.out.println(Arrays.toString(ps)); | |
} | |
} | |
class Person { | |
String name; | |
int score; | |
Person(String name, int score) {this.name = name; | |
this.score = score; | |
} | |
public String toString() {return this.name + "," + this.score; | |
} | |
} |
运行程序,我们会得到 ClassCastException
,即无法将Person
转型为 Comparable
。我们修改代码,让Person
实现 Comparable<T>
接口:
// sort | |
import java.util.Arrays; | |
public class Main {public static void main(String[] args) {Person[] ps = new Person[] {new Person("Bob", 61), | |
new Person("Alice", 88), | |
new Person("Lily", 75), | |
}; | |
Arrays.sort(ps); | |
System.out.println(Arrays.toString(ps)); | |
} | |
} | |
class Person implements Comparable<Person> { | |
String name; | |
int score; | |
Person(String name, int score) {this.name = name; | |
this.score = score; | |
} | |
public int compareTo(Person other) {return this.name.compareTo(other.name); | |
} | |
public String toString() {return this.name + "," + this.score; | |
} | |
} |
运行上述代码,可以正确实现按 name
进行排序。
也可以修改比较逻辑,例如,按 score
从高到低排序。请自行修改测试。
小结
使用泛型时,把泛型参数 <T>
替换为需要的 class 类型,例如:ArrayList<String>
,ArrayList<Number>
等;
可以省略编译器能自动推断出的类型,例如:List<String> list = new ArrayList<>();
;
不指定泛型参数类型时,编译器会给出警告,且只能将 <T>
视为 Object
类型;
可以在接口中定义泛型类型,实现此接口的类必须实现正确的泛型类型。
