前言
JDK自1.5版本引入泛型机制,代码中常用的容器类(如java.util.Collection和java.util.Map)都属于泛型类。泛型的引入带来了以下好处:
- 在使用集合类时,将以往JDK版本的类型错配报错,由运行时提前到了编译期,使得代码不再需要处理ClassCastException。
- 在访问泛型元素时,不再需要强制转换对象类型,代码更加简洁优雅。
- 泛型提高了代码复用率。
由于Java泛型属于语法糖,编译过后会将泛型信息擦除。相较于C++和C#的泛型,Java的泛型更像是伪泛型,因为JVM中没有泛型的概念,完全是编译器的magic。
代码示例
在编写泛型代码中,需要遵循Java的泛型命名规范。在Oracle官方教程中,最常用的泛型名称如下所示:
- E,表示元素,广泛用于JDK的集合框架中。
- K,表示Key。
- N,表示Number。
- T,表示Type。
- V,表示Value。
- S, U, V,表示第2、第3、第4个类型。
1.泛型类
我们可以看看ArrayList的类定义:
接下来我们写一个自定义泛型类:
代码清单java-sugar-generic1
TestGenericSimple的用法如下所示:
代码清单java-sugar-generic2
在intelliJ IDEA中,会对完整写法给出提示“Explicit type argument String can be replaced with <>”,这是因为可以使用尖括号<>让Java做类型推导。 而对于泛型类的raw type,编译器会给出警告“Unchecked call”,可以给实例化泛型类的方法或语句上新增@SuppressWarnings(“unchecked”)取消警告。上述3种写法中,推荐第2种,让Java自行做类型推导。 注:仅当泛型类在初始化时缺失了泛型参数,才被称作raw type,非泛型类没有raw type的说法。
2.泛型方法
泛型方法(静态或非静态)的定义和泛型类的定义类似,不过泛型的范围于仅局限于该方法内部。 与非泛型方法不同的是,需要将该方法内所有泛型用尖括号包含起来,并写在泛型方法返回值之前。测试代码如下所示:
代码清单java-sugar-generic3
在代码清单java-sugar-generic3中,我们定义了1个泛型类Pair,3个泛型方法,分别为compare,compare2,compare3。 可以看到返回值之前,需要写明该方法的所有泛型,如<K, V>、<T, K, V>。上述代码的调用如下所示:
代码清单java-sugar-generic4
在代码清单java-sugar-generic4中,有2种写法:完整写法和类型推导写法。同样intelliJ IDEA会对完整写法给出提示“Explicit type argument String can be replaced with <>”,建议实际代码中使用类型推导写法。
泛型的限制
泛型在使用上有一定的限制,主要在以下几个方面:
- 在初始化泛型类时,不能用原始类型作为Type Argument。
- 不能创建Type Parameter的实例,即不能E e = new E()。
- 不能声明泛型静态变量,因为静态变量属于类信息,是所有实例共享的内容,而泛型则属于实例信息。一个变量不能既是实例共享的,又是实例独享的。
- 不能对参数化的类型使用instanceof或者强制转换操作。
- 不能创建泛型数组。
- 泛型擦除后的raw type一致的参数化类型,不能重载方法。
泛型其他方面
在本博文中,展示了Java泛型的语法和用法。由于篇幅关系,将泛型的其他方面单独作为独立的文章进行叙述:
特别说明
在Oracle官方文档中,有关Type Parameter和Type Argument术语的说明如下:
Many developers use the terms “type parameter” and “type argument” interchangeably, but these terms are not the same.
When coding, one provides type arguments in order to create a parameterized type.
Therefore, the T in Foo
is a type parameter and the String in Foo f is a type argument. This lesson observes this definition when using these terms.
也就是在方法声明或者类声明中,T, E, K这种字符属于Type Parameter,而调用过程中的方法形参、类初始化参数属于Type Argument。 两者翻译含义相近,如有需要将以英文原文代替,不作汉语翻译。
附件
本博文所展示的源代码由此获得。
参考文献
[1] Josh Juneau.泛型:工作原理及其重要性[EB/OL].https://www.oracle.com/technetwork/cn/articles/java/juneau-generics-2255374-zhs.html,2019-07-02.
[2] The Java™ Tutorials - Generics[EB/OL].https://docs.oracle.com/javase/tutorial/java/generics/index.html,2019-07-02.
[3] The Java® Virtual Machine Specification[EB/OL].https://docs.oracle.com/javase/specs/jvms/se10/html/jvms-4.html#jvms-4.3,2019-07-04.