手写Java泛型,彻底掌握它!
“二哥,为什么要设计泛型啊?”三妹开门见山地问。
“三妹啊,听哥慢慢给你讲啊。”我说。
Java 在 1.5 时增加了泛型机制,据说专家们为此花费了 5 年左右的时间(听起来是相当不容易)。有了泛型之后,尤其是对集合类的使用,就变得更规范了。
看下面这段简单的代码。
ArrayList<String> list = new ArrayList<String>();
list.add("沉默王二");
String str = list.get(0);
“三妹,你能想象到在没有泛型之前该怎么办吗?”
“嗯,想不到,还是二哥你说吧。”
嗯,我们可以使用 Object 数组来设计 Arraylist
类。
class Arraylist {private Object[] objs;private int i = 0;public void add(Object obj) {objs[i++] = obj;}public Object get(int i) {return objs[i];}
}
然后,我们向 Arraylist
中存取数据。
Arraylist list = new Arraylist();
list.add("沉默王二");
list.add(new Date());
String str = (String)list.get(0);
“三妹,你有没有发现这两个问题?”
- Arraylist 可以存放任何类型的数据(既可以存字符串,也可以混入日期),因为所有类都继承自 Object 类。
- 从 Arraylist 取出数据的时候需要强制类型转换,因为编译器并不能确定你取的是字符串还是日期。
“嗯嗯,是的呢。”三妹说。
对比一下,你就能明显地感受到泛型的优秀之处:使用类型参数解决了元素的不确定性——参数类型为 String 的集合中是不允许存放其他类型元素的,取出数据的时候也不需要强制类型转换了。
动手设计一个泛型
“二哥,那怎么才能设计一个泛型呢?”
“三妹啊,你一个小白只要会用泛型就行了,还想设计泛型啊?!不过,既然你想了解,哥义不容辞。”
首先,我们来按照泛型的标准重新设计一下 Arraylist
类。
class Arraylist<E> {private Object[] elementData;private int size = 0;public Arraylist(int initialCapacity) {this.elementData = new Object[initialCapacity];}public boolean add(E e) {elementData[size++] = e;return true;}E elementData(int index) {return (E) elementData[index];}
}
一个泛型类就是具有一个或多个类型变量的类。Arraylist 类引入的类型变量为 E(Element,元素的首字母),使用尖括号 <>
括起来,放在类名的后面。
然后,我们可以用具体的类型(比如字符串)替换类型变量来实例化泛型类。
Arraylist<String> list = new Arraylist<String>();
list.add("沉默王三");
String str = list.get(0);
Date 类型也可以的。
Arraylist<Date> list = new Arraylist<Date>();
list.add(new Date());
Date date = list.get(0);
其次,我们还可以在一个非泛型的类(或者泛型类)中定义泛型方法。
class Arraylist<E> {public <T> T[] toArray(T[] a) {return (T[]) Arrays.copyOf(elementData, size, a.getClass());}
}
不过,说实话,泛型方法的定义看起来略显晦涩。来一副图吧(注意:方法返回类型和方法参数类型至少需要一个)。
现在,我们来调用一下泛型方法。
Arraylist<String> list = new Arraylist<>(4);
list.add("沉");
list.add("默");
list.add("王");
list.add("二");String [] strs = new String [4];
strs = list.toArray(strs);for (String str : strs) {System.out.println(str);
}
泛型限定符
然后,我们再来说说泛型变量的限定符 extends
。
在解释这个限定符之前,我们假设有三个类,它们之间的定义是这样的。
class Wanglaoer {public String toString() {