本文转载自微信公众号「潜行前行」,作者cscw 。转载本文请联系潜行前行公众号。
1 JAVA的Type类型体系
先了解下java的Type类型体系(类的类=>类型),Type是所有类型(原生类型-Class、参数化类型-Parameterizedtype、数组类型-GenericArrayType、类型变量-TypeVariable、基本类型-Class)的共同接口;前两篇反射和注解讲到的Class
2 泛型的概念
泛型: 把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型
3 泛型类和泛型方法的示例
- public class MainTest<T> {
- private T param;
- }
- public static void main(String[] args){
- MainTest<String> data = new MainTest<String>(){};
- ParameterizedType genType1 = (ParameterizedType)data.getClass().getGenericSuperclass();
- }
- public class MainTest{
- public static void main(String[] args){
- printData("siting");
- }
- static <T> T printData(T t){
- System.out.println(t);
- return t;
- }
- }
接口和抽象类都可以使用泛型
4 类型擦除
- public class MainTest {
- public static void main(String[] args){
- List<String> strArr = new ArrayList<>();
- List<Integer> intArr = new ArrayList<>();
- Type strClazz = strArr.getClass();
- Type intClazz = intArr.getClass();
- }
- }
- public class MainTest<T> {
- T param;
- public static void main(String[] args){
- MainTest<String> test = new MainTest<>();
- test.setParam("siting");
- }
- public T getParam() { return param; }
- public void setParam(T param) { this.param = param; }
- }
- public class com/MainTest {
- ...省略
- public static main([Ljava/lang/String;)V
- L0
- LINENUMBER 7 L0
- NEW com/MainTest
- DUP
- INVOKESPECIAL com/MainTest.<init> ()V
- ASTORE 1
- L1
- LINENUMBER 8 L1
- ALOAD 1
- LDC "siting" // 调用类型擦除后的setParam(Object)
- INVOKEVIRTUAL com/MainTest.setParam (Ljava/lang/Object;)V
- L2
- ...省略//getParam 的返回值是Object
- public getParam()Ljava/lang/Object;
- L0
- LINENUMBER 10 L0
- ALOAD 0
- GETFIELD com/MainTest.param : Ljava/lang/Object;
- ARETURN
- ...省略//setParam 的入参是Object
- public setParam(Ljava/lang/Object;)V
- L0
- LINENUMBER 11 L0
- ALOAD 0
- ALOAD 1
- PUTFIELD com/MainTest.param : Ljava/lang/Object;
- RETURN
- ...
- }
可以看出T(String)都被转换为Object类型,最初的初始化的String不见了
5 泛型的继承
- public class MainTest<T> {
- T param;
- static public class SubTest1 extends MainTest<String>{}
- static public class SubTest2<R> extends MainTest<R>{}
- //SubTest3继承的时原生类型
- static public class SubTest3 extends MainTest{}
- }
6 泛型变量TypeVariable
- public class MainTest<T> {
- List<T> param;
- public static void main(String[] args) throws Exception{
- Class clazz = MainTest.class;
- TypeVariable[] typeVariable = clazz.getTypeParameters();
- // 1
- Field field = clazz.getDeclaredField("param");
- ParameterizedType arrayType = (ParameterizedType)field.getGenericType();
- // interface List<E> 的泛型类型E被T,具体化,因此其被识别为 TypeVariable
- TypeVariable variable1 = (TypeVariable)arrayType.getActualTypeArguments()[0];
- // 2
- ParameterizedType type = (ParameterizedType)SubTest.class.getGenericSuperclass();
- TypeVariable variable2 = (TypeVariable)type.getActualTypeArguments()[0];
- }
- static class SubTest<R> extends MainTest<R>{}
- }
7 参数化类型ParameterizedType
- public interface ParameterizedType extends Type {
- //获取实际参数,List<String>里的String; 如果是List<T>则是TypeVariable类型
- Type[] getActualTypeArguments();
- // 获取原始类型List<String> -> List<E>
- Type getRawType();
- Type getOwnerType();
- }
- public class MainTest<T> {
- public static void main(String[] args){
- MainTest<String> str = new MainTest<String>();
- Class variable = str.getClass();
- Type genType1 = variable.getGenericSuperclass();
- }
- }
- // 1 子类继承泛型时,指定具体参数(可以是String等已知类型,也可以是子类的泛型参数)
- // 2 获取在类内部定义的泛型属性,需指定具体泛型参数
- // 3 局部代码,可以通过泛型的匿名内部子类(需指定具体泛型参数)获取ParameterizedType类型
- public class MainTest<T> {
- List<T> list;
- public static void main(String[] args) throws NoSuchFieldException {
- SubTest<String> str = new SubTest<>();
- // 方式一
- Class variable = str.getClass();
- // 父类是(521)ParameterizedType类型
- ParameterizedType genType = (ParameterizedType)variable.getGenericSuperclass();
- // (521)ParameterizedType类型的原生类型是(479)class com.MainTest
- Type clazz = genType.getRawType();
- //MainTest.class 的原生类型是 (479)class com.MainTest
- Class rawClazz = MainTest.class;
- //方式二,泛型属性
- Field field = rawClazz.getDeclaredField("list");
- //属性list 类型是(546)ParameterizedType类型List<T>
- ParameterizedType fieldType = (ParameterizedType)field.getGenericType();
- // 方式三
- MainTest<String> sub3 = new MainTest<String>(){};
- // clazz3是匿名子类
- Class clazz3 = sub3.getClass();
- //父类是(555)ParameterizedType类型
- ParameterizedType genType3 = (ParameterizedType) clazz3.getGenericSuperclass();
- // (555)ParameterizedType类型的原生类型是(479)class com.MainTest
- Type type3 = genType3.getRawType();
- }
- public static class SubTest<R> extends MainTest<R>{ }
- }
8 通配符(WildcardType)
无边界通配符:无界通配符 ? 可以适配任何引用类型:
- public static void print(List list){}
- ----->>>
- public static void print(List<?> list){}
上界限定通配符 < ? extends E>
- public static void print(List<? extends Number> list) {
- Number n = new Double("1.0");
- list.add(n);
- Number tmp = list.get(0);
- }
下界限定通配符 < ? super E>
- class Parent{ }
- class Child extends Parent{ }
- public class MainTest<T> {
- T param;
- public static void main(String[] args){
- MainTest<? super Child> parent_m = new MainTest<>();
- parent_m.setParam(new Child());
- Object parent = parent_m.getParam();
- }
- public T getParam() { return param; }
- public void setParam(T param) { this.param = param; }
- }
9 泛型数组(GenericArrayType)
- public interface GenericArrayType extends Type {
- //获得这个数组元素类型,即获得:A<T>(A<T>[])或 T(T[])
- Type getGenericComponentType();
- }
- public class MainTest<T> {
- T[] param;
- public static void main(String[] args) throws Exception{
- Class clazz = MainTest.class;
- Field field = clazz.getDeclaredField("param");
- GenericArrayType arrayType = (GenericArrayType)field.getGenericType();
- TypeVariable variable = (TypeVariable) arrayType.getGenericComponentType();
- }
- }