美文网首页
Java泛型详解

Java泛型详解

作者: Tinyspot | 来源:发表于2022-07-19 14:17 被阅读0次

    1. 泛型多边界

    • 语法 <T extends A & B & C>
    • 一个 class 边界 + 多个接口边界
    • 第一个是类,& 后面的只能是接口(即:单继承 多实现)

    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

    相关文章

      网友评论

          本文标题:Java泛型详解

          本文链接:https://www.haomeiwen.com/subject/vpcdirtx.html