使用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> { /** * 返回-1: 当前实例比参数o小 * 返回0: 当前实例与参数o相等 * 返回1: 当前实例比参数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>
接口: