Java学习_泛型
桐君过客 人气:0- 什么是泛型。
- Java标准库提供的
ArrayList
内部就是一个Object[]
数组,配合存储一个当前分配的长度,就可以充当“可变数组”。public class ArrayList { private Object[] array; private int size; public void add(Object e) {...} public void remove(int index) {...} public Object get(int index) {...} }
-
如果用上述
ArrayList
存储String
类型,会有这么几个缺点:-
需要强制转型;
-
不方便,易出错。
- 代码必须这么写:
ArrayList list = new ArrayList(); list.add("Hello"); // 获取到Object,必须强制转型为String: String first = (String) list.get(0);
很容易出现ClassCastException,因为容易“误转型”。
list.add(new Integer(123)); // ERROR: ClassCastException: String second = (String) list.get(1);
要解决上述问题,我们可以为
String
单独编写一种ArrayList。
public class StringArrayList { private String[] array; private int size; public void add(String e) {...} public void remove(int index) {...} public String get(int index) {...} }
这样一来,存入的必须是
String
,取出的也一定是String
,不需要强制转型,因为编译器会强制检查放入的类型。StringArrayList list = new StringArrayList(); list.add("Hello"); String first = list.get(0); // 编译错误: 不允许放入非String类型: list.add(new Integer(123));
问题暂时解决。然而,新的问题是,如果要存储
Integer
,还需要为Integer
单独编写一种ArrayList。实际上,还需要为其他所有class单独编写一种
ArrayList。
这是不可能的,JDK的class就有上千个,而且它还不知道其他人编写的class。
为了解决新的问题,我们必须把
ArrayList
变成一种模板:ArrayList<T>
public class ArrayList<T> { private T[] array; private int size; public void add(T e) {...} public void remove(int index) {...} public T get(int index) {...} }
T
可以是任何class。这样一来,我们就实现了:编写一次模版,可以创建任意类型的ArrayList。
// 创建可以存储String的ArrayList: ArrayList<String> strList = new ArrayList<String>(); // 创建可以存储Float的ArrayList: ArrayList<Float> floatList = new ArrayList<Float>(); // 创建可以存储Person的ArrayList: ArrayList<Person> personList = new ArrayList<Person>();
这样一来,既实现了编写一次,万能匹配,又通过编译器保证了类型安全:这就是泛型。
-
向上转型
- 在Java标准库中的
ArrayList<T>
实现了List<T>
接口,它可以向上转型为List<T>。
public class ArrayList<T> implements List<T> { ... } List<String> list = new ArrayList<String>();
类型
ArrayList<T>
可以向上转型为List<T>
。不能把ArrayList<Integer>
向上转型为ArrayList<Number>
或List<Number>
。ArrayList<Integer>和ArrayList<Number>两者完全没有继承关系。
- Java标准库提供的
-
使用泛型
-
使用
ArrayList
时,如果不定义泛型类型时,泛型类型实际上就是Object
-
编译器如果能自动推断出泛型类型,就可以省略后面的泛型类型。
// 可以省略后面的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
类型试试。1 // sort 2 import java.util.Arrays; 3 4 public class Main { 5 public static void main(String[] args) { 6 Person[] ps = new Person[] { 7 new Person("Bob", 61), 8 new Person("Alice", 88), 9 new Person("Lily", 75), 10 }; 11 Arrays.sort(ps); 12 System.out.println(Arrays.toString(ps)); 13 14 } 15 } 16 17 class Person { 18 String name; 19 int score; 20 Person(String name, int score) { 21 this.name = name; 22 this.score = score; 23 } 24 public String toString() { 25 return this.name + "," + this.score; 26 } 27 }
运行程序,我们会得到
ClassCastException
,即无法将Person
转型为Comparable
。我们修改代码,让Person
实现Comparable<T>
接口。1 // sort 2 import java.util.Arrays; 3 4 public class Main { 5 public static void main(String[] args) { 6 Person[] ps = new Person[] { 7 new Person("Bob", 61), 8 new Person("Alice", 88), 9 new Person("Lily", 75), 10 }; 11 Arrays.sort(ps); 12 System.out.println(Arrays.toString(ps)); 13 } 14 } 15 class Person implements Comparable<Person> { 16 String name; 17 int score; 18 Person(String name, int score) { 19 this.name = name; 20 this.score = score; 21 } 22 public int compareTo(Person other) { 23 return this.name.compareTo(other.name); 24 } 25 public String toString() { 26 return this.name + "," + this.score; 27 } 28 }
运行上述代码,可以正确实现按
name
进行排序。
-
-
未完待续
加载全部内容