为什么需要泛型
JDK 1.5 引入泛型。
在这之前,经常会看到这样的代码:
1 2 3
| ArrayList nameList = new ArrayList(); nameList.add("Franky"); String name = (String) nameList.get(0);
|
从代码中,我们不难发现问题:
- 当我们向数组列表中添加元素时,没有任何的类型安全检查。换言之,我们可以往列表中添加任意类型的对象。
- 当我们从数组列表中获取一个值时,必须进行强制类型转换。
而有了泛型之后:
1 2 3
| ArrayList<String> nameList = new ArrayList<String>(); nameList.add("Franky"); String name = nameList.get(0);
|
泛型的好处是显而易见的:
- 代码具有更好的可读性,能够清楚的知道类型。(例如:
ArrayList<String>
就可以这么理解:这是一个 String
类型的数组列表。)
- 在编译期提供类型安全检查。
- 所有的类型转换都是自动完成的。
使用泛型的注意事项
实例
下面的代码演示了如何定义泛型类,泛型方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| * 泛型类 */ public class Pair<F, S> {
private F first; private S second;
public Pair() { first = null; second = null; }
public Pair(F first, S second) { this.first = first; this.second = second; }
public F getFirst() { return first; }
public void setFirst(F first) { this.first = first; }
public S getSecond() { return second; }
public void setSecond(S second) { this.second = second; }
* 泛型方法 */ public static <T> T getThird(T third) { return third; }
* 带限制的泛型方法 */ public static <T extends Number & Comparable<T>> T getFourth(T fourth) { return fourth; }
* 实例化 */ public static <F, S> Pair<F, S> newPair(Class<F> cf, Class<S> cs) { try { return new Pair<F, S>(cf.newInstance(), cs.newInstance()); } catch (InstantiationException e) { return null; } catch (IllegalAccessException e) { return null; } }
@Override public String toString() { return "Pair [first=" + first + ", second=" + second + "]"; }
}
|
测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| import org.junit.Test;
public class PairTest {
@Test public void testGenericClass() { Pair<String, Integer> p1 = new Pair<String, Integer>(); p1.setFirst("one"); p1.setSecond(1); System.out.println(p1);
Pair<String, String> p2 = new Pair<String, String>("two", "two"); System.out.println(p2);
@SuppressWarnings("rawtypes") Pair p3 = new Pair(); System.out.println(p3); }
@Test public void testGetThird() { Integer value1 = Pair.getThird(3); System.out.println("Third is " + value1);
String value2 = Pair.getThird("three"); System.out.println("Third is " + value2); }
@Test public void testGetFourth() { Integer value1 = Pair.getFourth(4); System.out.println("Fourth is " + value1); }
@Test public void testGetPair() { Pair<String, String> pair = Pair.newPair(String.class, String.class); System.out.println(pair); }
}
|
总结
泛型的本质是类型的参数化。
这意味着我们编写的代码可以被很多不同类型的对象所重用。
泛型在使用方式类似于 C++ 中的模板。然而, Java 中的泛型是伪泛型,可以看作是一种“语法糖”,也就是编译器实现的一个小把戏。
因为,Java 中的泛型只存在于源代码,在编译的过程中,泛型会被替换成真实的类型(这个过程也叫做“类型擦除”)。
这种实现方式,也会给我们带来一定影响,例如,在重载方法的时候,下面的代码有一些 JDK 是无法编译通过的:
1 2 3 4 5 6 7 8 9 10
| public class ClassName { public void a(List<String> list){ } public void b(List<Integer> list){ } }
|
总的来说,泛型可以帮助我们提升代码的语义准确性,基于泛型设计类和方法,可以使得我们的代码更加灵活,可重用性更高。