【Reflect】泛型(generics)

Java泛型概述

 

  泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。

 

 

  在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的"任意化",

 

"任意化"带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型

可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,

在运行的时候才出现异常,这是一个安全隐患。

  泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。

 

运用泛型反射的经验法则

 

下面是两个典型的使用泛型的场景:

(1) 声明一个需要被参数化的类/接口。

 

 

(2) 使用一个参数化类。

 

 

当你声明一个类或者接口的时候你可以指明这个类或接口可以被参数化,java.util.List接口就是典型的例子。

你可以运用泛型机制创建一个标明存储的是String类型list,这样比你创建一个Object的list要更好。

 

 

当你想在运行期参数化类型本身,比如你想检查java.util.List类的参数化类型,你是没有办法能知道

他具体的参数化类型是什么。这样一来这个类型就可以是一个应用中所有的类型。但是,当你检查一个

 

 

使用了被参数化的类型的变量或者方法,你可以获得这个被参数化类型的具体参数。

总之:你不能在运行期获知一个被参数化的类型的具体参数类型是什么,但是你可以在用到这个被参数化类型的方法

 

 

以及变量中找到他们,换句话说就是获知他们具体的参数化类型。


泛型方法返回类型

 

 

如果你获得了java.lang.reflect.Method对象,那么你就可以获取到这个方法的泛型返回类型信息。

如果方法是在一个被参数化类型之中那么你无法获取他的具体类型,但是如果方法返回一个泛型类那么你就可以获得

 

 

这个泛型类的具体参数化类型。

 

下面这个例子定义了一个类这个类中的方法返回类型是一个泛型类型:

package com.lanhuigu.reflect.generics;

import java.util.ArrayList;
import java.util.List;

public class MyClass {
    public List<String> stringList = new ArrayList<>();

    public List<String> getStringList() {
        return stringList;
    }

    public void setStringList(List<String> list) {
        this.stringList = list;
    }
}

我们可以获取getStringList()方法的泛型返回类型,换句话说,我们可以检测到getStringList()方法返回的是List而不仅仅只是一个List。

如下例:

package com.lanhuigu.reflect.generics;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class Test1 {
    public static void main(String[] args) throws NoSuchMethodException {
        /** 获取Class对象 */
        Class myClass = MyClass.class;

        /** 获取Method对象 */
        Method method = myClass.getMethod("getStringList", null);

        /** 获取方法返回泛型 */
        Type returnType = method.getGenericReturnType();
        if (returnType instanceof ParameterizedType) {
            ParameterizedType type = (ParameterizedType) returnType;
            Type[] typeArguments = type.getActualTypeArguments();
            for (Type typeArgument : typeArguments) {
                Class typeArgClass = (Class) typeArgument;
                System.out.println("typeArgClass = " + typeArgClass);
            }
        }
    }
}

这段代码会打印出"typeArgClass = java.lang.String",Type[]数组typeArguments只有一个结果,

一个代表java.lang.String的Class类的实例。Class类实现了Type接口。


泛型方法参数类型

 

你同样可以通过反射来获取方法参数的泛型类型,这个类中的方法的参数是一个被参数化的List:

 

你可以像这样来获取方法的泛型参数:

package com.lanhuigu.reflect.generics;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

public class Test2 {
    public static void main(String[] args) throws NoSuchMethodException {
        /** 获取Class对象 */
        Class myClass = MyClass.class;

        /** 获取Method对象 */
        Method method = myClass.getMethod("setStringList", List.class);

        /** 获取方法参数泛型 */
        Type[] genericParameterTypes = method.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes) {
            if (genericParameterType instanceof ParameterizedType) {
                ParameterizedType aType = (ParameterizedType) genericParameterType;
                Type[] parameterArgTypes = aType.getActualTypeArguments();
                for (Type parameterArgType : parameterArgTypes) {
                    Class parameterArgClass = (Class) parameterArgType;
                    System.out.println("parameterArgClass = " + parameterArgClass);
                }
            }
        }
    }
}

这段代码会打印出"parameterArgType = java.lang.String"。Type[]数组parameterArgTypes只有一个结果,

一个代表java.lang.String的Class类的实例。Class类实现了Type接口。

泛型变量类型

同样可以通过反射来访问公有(Public)变量的泛型类型,无论这个变量是一个类的静态成员变量或是实例成员变量。

如下例:

package com.lanhuigu.reflect.generics;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class Test3 {
    public static void main(String[] args) throws NoSuchFieldException {
        /** 获取Class对象 */
        Class myClass = MyClass.class;

        /** 获取Field对象 */
        Field field = myClass.getField("stringList");

        /** 获取属性泛型 */
        Type genericFieldType = field.getGenericType();
        if (genericFieldType instanceof ParameterizedType) {
            ParameterizedType aType = (ParameterizedType) genericFieldType;
            Type[] fieldArgTypes = aType.getActualTypeArguments();
            for (Type fieldArgType : fieldArgTypes) {
                Class fieldArgClass = (Class) fieldArgType;
                System.out.println("fieldArgClass = " + fieldArgClass);
            }
        }
    }
}

这段代码会打印出"fieldArgClass = java.lang.String"。Type[]数组fieldArgClass只有一个结果,

一个代表java.lang.String的Class类的实例。Class类实现了Type接口。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值