Java泛型详解

2022-07-19  本文已影响0人  Tinyspot

1. 泛型多边界

https://developer.aliyun.com/article/24356
https://www.jianshu.com/p/0f2a9b9afde4

2. 泛型类派生子类

// 2.1 子类也是泛型,子类和父类的泛型标识要一致
public class ResultDTO<T, S> extends Result<T, S> {
}
ResultDTO<QueryDTO, QueryVO> resultDTO = new ResultDTO<>();

// 2.2 子类不是泛型类,父类要明确泛型的数据类型
public class ResultDTO extends Result<QueryDTO, QueryVO> {
}
ResultDTO resultDTO = new ResultDTO();

3. 获取泛型参数类型

3.1 继承泛型类

public class Result<T, S> {
}
public class ResultDTO extends Result<QueryDTO, QueryVO> {
}

public static void main(String[] args) {
    ParameterizedType parameterizedType = (ParameterizedType) ResultDTO.class.getGenericSuperclass();
    Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
    for (Type genericParameterType : actualTypeArguments) {
        // 注意 genericParameterType.getClass() 是得到 class 文件信息,不能使用这种方式
        Class clazz = (Class) genericParameterType;
    }
    Class<QueryDTO> queryDTOClass = (Class<QueryDTO>) actualTypeArguments[0];
    Class<QueryVO> queryVOClass = (Class<QueryVO>) actualTypeArguments[1];
    String beanName = queryVOClass.getName();
    String className = queryVOClass.getSimpleName();
}

3.2 实现泛型接口

public interface Result<T, S> {
}
public class ResultDTO implements Result<QueryDTO, QueryVO> {
}

public static void main(String[] args) {
    /**
     * Type[] genericInterfaces = ResultDTO.class.getGenericInterfaces();
     * Type[] 数组,代表类实现的多个接口
     * ResultDTO implements Result<QueryDTO, QueryVO> {} 只实现了一个接口,取第一个元素
     */
    Type genericInterface = ResultDTO.class.getGenericInterfaces()[0];
    ParameterizedType parameterizedType = (ParameterizedType) genericInterface;
    Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
    Class<QueryDTO> queryDTOClass = (Class<QueryDTO>) actualTypeArguments[0];
    String beanName = queryDTOClass.getName();
}

4. 泛型擦除

Java 泛型是 1.5 引入,为了兼容 1.5 之前的代码,在编译器里通过擦除来支持泛型

例如:

List<Integer> intList = new ArrayList<>();
List<String> strList = new ArrayList<>();
// intList.getClass().getName() 和 strList.getClass().getName() 都是 java.util.ArrayList
System.out.println(intList.getClass() == strList.getClass()); // true

List<String>.class、List<Integer>.class 在 JVM 层面只有 List.class

// public TypeVariable<Class<T>>[] getTypeParameters() {}
List<User> users = new ArrayList<>();
System.out.println(Arrays.toString(users.getClass().getTypeParameters())); // [E]

getTypeParameters 返回类型参数,查看上面并不是返回 Integer,而是 [E] (一个占位符)

编译后查看 class 文件
进入class目录 javap -v xxx.class or javap -v xxx(文件后缀.class可省略)

List<Person> list = new ArrayList<>();
// javap 编译后,泛型 Person 被擦除 (泛型Person 并不是字节码中的指令,只是个符号,编译后被擦除)

 Code:
      stack=2, locals=2, args_size=1
         0: new     #2    // class java/util/ArrayList(编译后只是 ArrayList)

References

上一篇下一篇

猜你喜欢

热点阅读