美文网首页
基于ParameterizedType实现泛型类类型参数化

基于ParameterizedType实现泛型类类型参数化

作者: 几行代码 | 来源:发表于2019-02-23 11:48 被阅读0次

    在上一篇中我们用到了这个方法:

    public static <T> T getInstance(Object object, int i) {
            if (object != null) {
                return (T) ((ParameterizedType) object.getClass()
                        .getGenericSuperclass())
                        .getActualTypeArguments()[i];
            }
            return null;
        }
    

    在这篇中就来分析一下什么是ParameterizedType,它有什么作用。
    ParameterizedType是 JDK7 开始, java.lang.reflect 提供了Interface ParameterizedType. 通过实现这个接口, 我们可以实现泛型类的类型的参数化。
    先来看看它的源码:

    /**
     * ParameterizedType represents a parameterized type such as
     * Collection&lt;String&gt;.
     *
     * <p>A parameterized type is created the first time it is needed by a
     * reflective method, as specified in this package. When a
     * parameterized type p is created, the generic type declaration that
     * p instantiates is resolved, and all type arguments of p are created
     * recursively. See {@link java.lang.reflect.TypeVariable
     * TypeVariable} for details on the creation process for type
     * variables. Repeated creation of a parameterized type has no effect.
     *
     * <p>Instances of classes that implement this interface must implement
     * an equals() method that equates any two instances that share the
     * same generic type declaration and have equal type parameters.
     *
     * @since 1.5
     */
    public interface ParameterizedType extends Type {
        /**
         * Returns an array of {@code Type} objects representing the actual type
         * arguments to this type.
         *
         * <p>Note that in some cases, the returned array be empty. This can occur
         * if this type represents a non-parameterized type nested within
         * a parameterized type.
         *
         * @return an array of {@code Type} objects representing the actual type
         *     arguments to this type
         * @throws TypeNotPresentException if any of the
         *     actual type arguments refers to a non-existent type declaration
         * @throws MalformedParameterizedTypeException if any of the
         *     actual type parameters refer to a parameterized type that cannot
         *     be instantiated for any reason
         * @since 1.5
         */
        Type[] getActualTypeArguments();
    
        /**
         * Returns the {@code Type} object representing the class or interface
         * that declared this type.
         *
         * @return the {@code Type} object representing the class or interface
         *     that declared this type
         * @since 1.5
         */
        Type getRawType();
    
        /**
         * Returns a {@code Type} object representing the type that this type
         * is a member of.  For example, if this type is {@code O<T>.I<S>},
         * return a representation of {@code O<T>}.
         *
         * <p>If this type is a top-level type, {@code null} is returned.
         *
         * @return a {@code Type} object representing the type that
         *     this type is a member of. If this type is a top-level type,
         *     {@code null} is returned
         * @throws TypeNotPresentException if the owner type
         *     refers to a non-existent type declaration
         * @throws MalformedParameterizedTypeException if the owner type
         *     refers to a parameterized type that cannot be instantiated
         *     for any reason
         * @since 1.5
         */
        Type getOwnerType();
    }
    
    • 发现ParameterizedType是一个接口,并继承Type这个对象,Type是什么呢我们点进去也看看:
    /**
     * Type is the common superinterface for all types in the Java
     * programming language. These include raw types, parameterized types,
     * array types, type variables and primitive types.
     *
     * @since 1.5
     */
    public interface Type {
        /**
         * Returns a string describing this type, including information
         * about any type parameters.
         *
         * @implSpec The default implementation calls {@code toString}.
         *
         * @return a string describing this type
         * @since 1.8
         */
        default String getTypeName() {
            return toString();
        }
    }
    

    这是官方的注释:

    Type is the common superinterface for all types in the Java programming language. These include raw types, parameterized types, array types, type variables and primitive types.
    Type 是Java编程语言中所有类型的通用超级接口。这些类型包括原始类型、参数化类型、数组类型、类型变量和基元类型。
    这里解释的很清楚了,Type接口是Java编程语言中所有类型的通用超级接口。

    下面我们继续看ParameterizedType:

    A parameterized type is created the first time it is needed by a reflective method, as specified in this package. When a parameterized type p is created, the generic type declaration that p instantiates is resolved, and all type arguments of p are created
    recursively. See {@link java.lang.reflect.TypeVariable TypeVariable} for details on the creation process for type variables.
    Repeated creation of a parameterized type has no effect.

    大概意思是说:ParameterizedType是在反射方法第一次需要时创建的,如包中指定的。当创建参数化类型p时,解析p实例化的泛型类型声明,并且递归地创建p的所有类型参数。有关类型变量创建过程的详细信息,请参见@link java.lang.reflect.typevariable typevariable。
    重复创建参数化类型没有效果。

    怎么来判断参数化类型呢?
    通过下面例子来说明

    public class ParameterizedTypeBean {
        List<String> listString;
        List list;
        Map<String,Long> mapString;
        Map map;
        Map.Entry<Long,Short> mapLong;
    }
    

    测试:

    Field[] declaredFields = ParameterizedTypeBean.class.getDeclaredFields(); // 反射获取字段
            for (Field field : declaredFields) {
                // 是否是 ParameterizedType 参数化类型
                System.out.println(field.getName() + ": " + (field.getGenericType() instanceof ParameterizedType));
            }
    

    结果打印:

    listString: true
    list: false
    mapString: true
    map: false
    mapLong: true
    

    从打印结果看来,具有<>(泛型)符号的变量是参数化类型。

    我们分别来看ParameterizedType内部的三个方法:

    该方法返回一个Type数组
    Type[] getActualTypeArguments();

    测试代码:

    Field[] declaredFields = ParameterizedTypeBean.class.getDeclaredFields(); // 反射获取字段
            for (Field field : declaredFields) {
                if (field.getGenericType() instanceof ParameterizedType) {
    
                    ParameterizedType genericType = (ParameterizedType) field.getGenericType();
    
                    System.out.print("变量类型 = " + genericType.getTypeName() + "   ");
                    System.out.print("变量名称 = " + field.getName() + "   ");
    
                    // 泛型类型的数组
                    Type[] actualTypeArguments = genericType.getActualTypeArguments();
    
                    for (Type type: actualTypeArguments) {
                        System.out.print("泛型类型 = " + type.getTypeName()  + "   ");
                    }
                    System.out.println();
                    System.out.println();
                }
            }
    

    打印结果:

    变量类型 = java.util.List<java.lang.String>   变量名称 = listString   泛型类型 = java.lang.String   
    
    变量类型 = java.util.Map<java.lang.String, java.lang.Long>   变量名称 = mapString   泛型类型 = java.lang.String   泛型类型 = java.lang.Long   
    
    变量类型 = java.util.Map$Entry<java.lang.Long, java.lang.Short>   变量名称 = mapLong   泛型类型 = java.lang.Long   泛型类型 = java.lang.Short   
    

    ps: 从打印结果返回来看,getActualTypeArguments()返回了一个Type数组,数组里是参数化类型的参数。

    Type getRawType();

    测试代码:

    Field[] declaredFields = ParameterizedTypeBean.class.getDeclaredFields(); // 反射获取字段
            for (Field field : declaredFields) {
                if (field.getGenericType() instanceof ParameterizedType) {
    
                    ParameterizedType genericType = (ParameterizedType) field.getGenericType();
    
                    System.out.print("变量 名称= " + field.getName() + "   ");
    
                    // 获取变量的类型 genericType.getRawType()
                    System.out.print("getRawType() = " + genericType.getRawType().getTypeName());
    
                    System.out.println();
                    System.out.println();
                }
            }
    

    打印结果:

    变量 名称= listString   getRawType() = java.util.List
    
    变量 名称= mapString   getRawType() = java.util.Map
    
    变量 名称= mapLong   getRawType() = java.util.Map$Entry
    

    PS:从打印结果来看,getRawType()是变量的类型

    Type getOwnerType();

    测试代码:

    Field[] declaredFields = ParameterizedTypeBean.class.getDeclaredFields(); // 反射获取字段
            for (Field field : declaredFields) {
                if (field.getGenericType() instanceof ParameterizedType) {
                    ParameterizedType genericType = (ParameterizedType) field.getGenericType();
    
                    System.out.print("变量 名称= " + field.getName() + "   ");
    
                    Type ownerType = genericType.getOwnerType();
                    if (ownerType != null) {
                        System.out.print("getOwnerType() = " + ownerType.getTypeName());
                    } else {
                        System.out.print("getOwnerType() = null");
                    }
    
                    System.out.println();
                    System.out.println();
                }
            }
    

    打印结果:

    变量 名称= listString   getOwnerType() = null
    
    变量 名称= mapString   getOwnerType() = null
    
    变量 名称= mapLong   getOwnerType() = java.util.Map
    

    PS:从打印结果来看,前面两个都为null,最后一个为Map类型

    前两个为什么会返回 null 呢。看一下官网的注释:

    Returns a {@code Type} object representing the type that this type is a member of. For example, if this type is {@code O<T>.I<S>}, return a representation of {@code O<T>}.

    大概意思是说:返回@code type对象,该对象表示此类型所属的类型。例如,如果此类型为@code o<t>.i<s>,则返回@code o<t>的表示形式。
    也就是说:

    O<T>.I<S>类型的变量,调用getOwnerType()会返回O<T>

    官网还有一句:

    If this type is a top-level type, {@code null} is returned.
    如果此类型是顶级类型,则返回@code null。

    这就解释为什么会打印 null 了。

    总结:

    1.Type 是Java编程语言中所有类型的通用超级接口。这些类型包括原始类型、参数化类型、数组类型、类型变量和基元类型。

    • 内部的 getTypeName() 方法会返回对应类型的全限定类名。

    2.只有具有<>(泛型)符号的变量是参数化类型。
    3.getActualTypeArguments()返回了一个Type数组,数组里是参数化类型的参数,可以根据这个方法获取到 “泛型的类型”。
    4.getRawType()是获取变量的类型。
    5.getOwnerType()方法对于O<T>.I<S>类型的变量,会返回O<T>,例如:Map.Entry<Long,Short> mapLong,会返回java.util.Map,而不是java.util.Entry。

    基于ParameterizedType获取泛型参数类型的实例:https://www.jianshu.com/p/5a7f36c7dd9e

    相关文章

      网友评论

          本文标题:基于ParameterizedType实现泛型类类型参数化

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