【小家Java】你真的了解Java泛型参数吗?细说java.lang.reflect.Type(ParameterizedType、TypeVariable、WildcardType...)(下)

简介: 【小家Java】你真的了解Java泛型参数吗?细说java.lang.reflect.Type(ParameterizedType、TypeVariable、WildcardType...)(下)

Class(原始/基本类型)


**Type的直接子类只有一个,也就是Class,代表着类型中的原始类型以及基本类型。**Class —— 反射基石


其意义为:类的抽象,即对“类”做描述:比如类有修饰、字段、方法等属性,有获得该类的所有方法、所有公有方法等方法。同时,Class也是Java类型中最重要的一种,表示原始类型(引用类型)及基本类型。


与泛型有关的类型不能和原始类型统一到Class的原因


产生泛型擦除的原因


原始类型和新产生的类型都应该统一成各自的字节码文件类型对象。但是由于泛型不是最初Java中的成分。如果真的加入了泛型,涉及到JVM指令集的修改,这是非常致命的(简单的说就是Java要向下兼容,所以它的泛型是个假东西)


Java 引入泛型擦除的原因是避免因为引入泛型而导致运行时创建不必要的类。那我们其实就可以通过定义类的方式,在类信息中保留泛型信息,从而在运行时获得这些泛型信息。

简而言之,Java 的泛型擦除是有范围的,即类定义中的泛型是不会被擦除的

    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<String, Integer>();
        Type type = map.getClass().getGenericSuperclass(); // 获取HashMap父类AbstractMap<K,V>  请注意:此处为<K,V>
        ParameterizedType parameterizedType = ParameterizedType.class.cast(type);
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); // 两个类型  一个是K,一个是V
        for (Type typeArgument : actualTypeArguments) {
            System.out.println(typeArgument.getTypeName()); //k,v(泛型消失了)
        }
    }
// 泛型不消失的情况对比
public class Main {
    private static class HashMapEx<K, V> extends HashMap<K, V> {
        public HashMapEx() {
            super();
        }
    }
    public static void main(String[] args) {
        // 此处必须用匿名内部类的方式写,如果使用new HashMapEx<String,Integer> 效果同上
        Map<String, Integer> map = new HashMap<String, Integer>() {
        };
        Type type = map.getClass().getGenericSuperclass(); // 获取HashMapEx父类HashMap<K,V>
        ParameterizedType parameterizedType = ParameterizedType.class.cast(type);
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); // 两个类型  一个是K,一个是V
        for (Type typeArgument : actualTypeArguments) {
            System.out.println(typeArgument.getTypeName()); //k,v(泛型消失了)
        }
    }
}

getSuperclass 返回直接继承的父类(由于编译擦除,没有显示泛型参数)

getGenericSuperclass :返回直接继承的父类(包含泛型参数) 1.5后提供



    public static void main(String[] args) {
        // 此处必须用匿名内部类的方式写,如果使用new HashMapEx<String,Integer> 效果同上
        Map<String, Integer> map = new HashMap<String, Integer>() {
        };
        System.out.println(map.getClass().getSuperclass()); //class java.util.HashMap
        System.out.println(map.getClass().getGenericSuperclass()); //java.util.HashMap<java.lang.String, java.lang.Integer>
        // 但是如果是不带泛型的,两者等价
        Integer i = new Integer(1);
        System.out.println(i.getClass().getSuperclass()); //class java.lang.Number
        System.out.println(i.getClass().getGenericSuperclass()); //class java.lang.Number
    }


Java中如何引入泛型


为了使用泛型又不真正引入泛型,Java采用泛型擦除机制来引入泛型。Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换的麻烦。但是,一旦编译完成,所有的和泛型有关的类型全部擦除。


Class不能表达与泛型有关的类型


因此,与泛型有关的参数化类型、类型变量类型、限定符类型 、泛型数组类型这些类型编译后全部被打回原形,在字节码文件中全部都是泛型被擦除后的原始类型,并不存在和自身类型对应的字节码文件。所以和泛型相关的新扩充进来的类型不能被统一到Class类中。


与泛型有关的类型在Java中的表示


为了通过反射操作这些类型以迎合实际开发的需要,Java就新增了ParameterizedType, TypeVariable<D>, GenericArrayType, WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型。


入Type的原因


为了程序的扩展性,最终引入了Type接口作为Class和ParameterizedType, TypeVariable, GenericArrayType, WildcardType这几种类型的总的父接口。这样可以用Type类型的参数来接受以上五种子类的实参或者返回值类型就是Type类型的参数。统一了与泛型有关的类型和原始类型Class


Type接口中没有方法的原因


从上面看到,Type的出现仅仅起到了通过多态来达到程序扩展性提高的作用,没有其他的作用。因此Type接口的源码中没有任何方法。


最后用一个我们最常用的例子:反射获取泛型类型。给出解决方案如下


反射获取类的泛型类型


这个还是非常有用的,比如我们在常用的泛型基类设计中可以这么写


public class BaseDaoImpl<T> implements BaseDao<T> {
  // 它代表着实际类型
    private Class<T> beanClass;
    @SuppressWarnings("unchecked")
    public BaseDaoImpl() {
        ParameterizedType parameterizedType=(ParameterizedType)this.getClass().getGenericSuperclass();
        beanClass=(Class<T>) parameterizedType.getActualTypeArguments()[0];
    }
    // 省略具体的操作....
}


说明:Class类有两个"雷同"的方法:

    public native Class<? super T> getSuperclass(); //返回直接继承的父类(不显示泛型参数)
    // @since 1.5
    public Type getGenericSuperclass(); // 返回直接继承的父类 显示泛型参数


从返回值或许就能看出差异。他俩从执行结果上,更能看出差异:


Student.class.getSuperclass() class cn.test.Person
Student.class.getGenericSuperclass()  cn.test.Person<cn.test.Test>

总结


我们知道,Type是JDK5开始引入的,其引入主要是为了泛型,没有泛型的之前,只有所谓的原始类型。此时,所有的原始类型都通过字节码文件类Class类进行抽象。Class类的一个具体对象就代表一个指定的原始类型。


泛型出现之后,也就扩充了数据类型。从只有原始类型扩充了参数化类型、类型变量类型、泛型数组类型,也就是Type的子接口。

 那为什么没有统一到Class下,而是增加一个Type呢?(Class也是种类的意思,Type是类型的意思)

 

 是为了程序的扩展性,最终引入了Type接口作为Class,ParameterizedType,GenericArrayType,TypeVariable和WildcardType这几种类型的总的父接口。

 这样实现了Type类型参数接受以上五种子类的实参或者返回值类型就是Type类型的参数。


List<T ? entends>[]:这里的List就是ParameterizedType,T就是TypeVariable,T ? entends就是WildcardType(注意,WildcardType不是Java类型,而是一个表达式),整个List<T ? entends>[]就是GenericArrayType

相关文章
|
2月前
|
Java API
[Java]泛型
本文详细介绍了Java泛型的相关概念和使用方法,包括类型判断、继承泛型类或实现泛型接口、泛型通配符、泛型方法、泛型上下边界、静态方法中使用泛型等内容。作者通过多个示例和测试代码,深入浅出地解释了泛型的原理和应用场景,帮助读者更好地理解和掌握Java泛型的使用技巧。文章还探讨了一些常见的疑惑和误区,如泛型擦除和基本数据类型数组的使用限制。最后,作者强调了泛型在实际开发中的重要性和应用价值。
25 0
[Java]泛型
|
14天前
|
Java
在Java中定义一个不做事且没有参数的构造方法的作用
Java程序在执行子类的构造方法之前,如果没有用super()来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用super()来调用父类中特定的构造方法,则编译时将发生错误,因为Java程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。
|
2月前
|
存储 安全 Java
🌱Java零基础 - 泛型详解
【10月更文挑战第7天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
15 1
|
2月前
|
Java 语音技术 容器
java数据结构泛型
java数据结构泛型
27 5
|
2月前
|
存储 Java 编译器
Java集合定义其泛型
Java集合定义其泛型
19 1
|
3月前
|
Java 编译器 容器
Java——包装类和泛型
包装类是Java中一种特殊类,用于将基本数据类型(如 `int`、`double`、`char` 等)封装成对象。这样做可以利用对象的特性和方法。Java 提供了八种基本数据类型的包装类:`Integer` (`int`)、`Double` (`double`)、`Byte` (`byte`)、`Short` (`short`)、`Long` (`long`)、`Float` (`float`)、`Character` (`char`) 和 `Boolean` (`boolean`)。包装类可以通过 `valueOf()` 方法或自动装箱/拆箱机制创建。
39 9
Java——包装类和泛型
|
2月前
|
存储 算法 Java
java制作海报六:Graphics2D的RenderingHints方法参数详解,包括解决文字不清晰,抗锯齿问题
这篇文章是关于如何在Java中使用Graphics2D的RenderingHints方法来提高海报制作的图像质量和文字清晰度,包括抗锯齿和解决文字不清晰问题的技术详解。
57 0
java制作海报六:Graphics2D的RenderingHints方法参数详解,包括解决文字不清晰,抗锯齿问题
|
2月前
|
存储 Java 编译器
【用Java学习数据结构系列】初识泛型
【用Java学习数据结构系列】初识泛型
20 2
|
2月前
|
Java
java构造方法时对象初始化,实例化,参数赋值
java构造方法时对象初始化,实例化,参数赋值
55 1
|
2月前
|
安全 Java 编译器
Java基础-泛型机制
Java基础-泛型机制
16 0