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

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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容