解析反射

原创
2019/03/10 23:52
阅读数 601

反射离不开Class.forName(),我们先从Class.forName说起。

上一篇我们说要得到一个类的实例有4个方法:new,反射,克隆,反序列化。

反射可以跟new一个对象有相同的效果。例如

public class Company {
    private String a;
    private String b;

    @Override
    public String toString() {
        return "Company{" +
                "a='" + a + '\'' +
                ", b='" + b + '\'' +
                '}';
    }

    public Company() {
        this.a = "A";
        this.b = "B";
    }
}
public class CompanyInstance {
    private static Company company = new Company();

    public static void main(String[] args) {
        System.out.println(company);
    }
}

运行结果

Company{a='A', b='B'}

又可以写成如下

public class CompanyInstance {

    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        System.out.println(Class.forName("com.guanjian.Company").newInstance());
    }
}

运行结果

Company{a='A', b='B'}

虽然效果一样,但他们的过程并不一样。 首先,newInstance( )是一个方法,而new是一个关键字;其次,Class下的newInstance()的使用有局限,因为它生成对象只能调用无参的构造函数,而使用 new关键字生成对象没有这个限制。

newInstance()的时候是使用的上篇说的类装载机制的,它会走完全部过程。具体可以看 浅析类装载 ,而new一个实例的时候,走的流程不太一样,它会先在JVM内部先去寻找该类的Class实例,然后依照该Class实例的定义,依葫芦画瓢,把该类的实例给生成出来。但如果找不到该类的Class实例,则会走上篇说的装载流程。 其中JDK的Class实例一般是在jvm启动时用启动类加载器完成加载,用户的Class实例则是在用到的时候再加载。

Class.forName()被重载为有一个参数和三个参数的,我们来看一下其源码

@CallerSensitive
public static Class<?> forName(String className)
            throws ClassNotFoundException {
    Class<?> caller = Reflection.getCallerClass();
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
@CallerSensitive
public static Class<?> forName(String name, boolean initialize,
                               ClassLoader loader)
    throws ClassNotFoundException
{
    Class<?> caller = null;
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        // Reflective call to get caller class is only needed if a security manager
        // is present.  Avoid the overhead of making this call otherwise.
        caller = Reflection.getCallerClass();
        if (sun.misc.VM.isSystemDomainLoader(loader)) {
            ClassLoader ccl = ClassLoader.getClassLoader(caller);
            if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
                sm.checkPermission(
                    SecurityConstants.GET_CLASSLOADER_PERMISSION);
            }
        }
    }
    return forName0(name, initialize, loader, caller);
}

其中Reflection.getCallerClass()源码如下

@CallerSensitive
public static native Class<?> getCallerClass();

这是一个跟C语言交互的,用户无权限调用的方法,只能被 bootstrap class loaderextension class loader 调用的,这两个加载类后面再说。意思是返回调用者的Class实例。

private static native Class<?> forName0(String name, boolean initialize,
                                        ClassLoader loader,
                                        Class<?> caller)
    throws ClassNotFoundException;

它的第二个参数boolean initialize表示是否要初始化该类,单参Class.forName()默认true是要初始化的,三参的Class.forName()由你自己选择。一旦初始化,就会触发目标对象的 static块代码执行,static参数也也会被再次初始化。当然如果你使用了三个参数的Class.forName(),并调用了newInstance()以后,是肯定会初始化的。

public class CompanyInstance {

    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        System.out.println(Class.forName("com.guanjian.Company",false,Thread.currentThread().getContextClassLoader()).newInstance());
    }
}

运行结果

Company{a='A', b='B'}

现在我们重点要说的是它的ClassLoader,这个才是真正装载类的核心组件。所有的Class都是由ClassLoader进行加载的,ClassLoader负责通过各种方式将Class信息的二进制字节码数据流读入系统,然后交给JVM虚拟机进行连接、初始化等操作。ClassLoader是一个抽象类,我们来看一下它的部分源码。

public abstract class ClassLoader {

    private static native void registerNatives();
    static {
        registerNatives();
    }

    // The parent class loader for delegation
    // Note: VM hardcoded the offset of this field, thus all new fields
    // must be added *after* it.
    private final ClassLoader parent;

我们来看一下它部分对外公开的public方法。

public Class<?> loadClass(String name) throws ClassNotFoundException {
    return loadClass(name, false);
}
static ClassLoader getClassLoader(Class<?> caller) {
    // This can be null if the VM is requesting it
    if (caller == null) {
        return null;
    }
    // Circumvent security check since this is package-private
    return caller.getClassLoader0();
}

public loadClass方法的作用为给定一个类名,加载一个类,返回代表这个类的Class实例,如果找不到类,则返回ClassNotFoundException异常。它调用了protected loadClass方法。源码如下(加了注释)

protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
    //对这个名称产生一个锁对象,并进行加锁处理
    synchronized (getClassLoadingLock(name)) {
        // First, check if the class has already been loaded
        //findLoadedClass的底层也是C语言交互实现的,应该是在JVM内存中查找该类的Class实例
        Class<?> c = findLoadedClass(name);
        //如果在JVM内存中找不到该类的Class实例
        if (c == null) {
            long t0 = System.nanoTime();
            try {//parent为该加载器的双亲,具体会在后面介绍,如果双亲对象不为null,使用双亲加载
                if (parent != null) {
                    c = parent.loadClass(name, false);
                } else {
                    //如果找不到双亲,启用最高权限的BootstrapClassLoader加载,BootstrapClassLoader在Java中没有对象,是用C语言实现的
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                // ClassNotFoundException thrown if class not found
                // from the non-null parent class loader
            }
            //如果找不到最高权限的加载器
            if (c == null) {
                // If still not found, then invoke findClass in order
                // to find the class.
                long t1 = System.nanoTime();
                //直接抛出异常
                c = findClass(name);

                // this is the defining class loader; record the stats
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
        }
        //如果在JVM内存中找到该类的Class实例,当前加载器自己处理
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
}

加锁处理片段代码

private final ConcurrentHashMap<String, Object> parallelLockMap;
protected Object getClassLoadingLock(String className) {
    //加载器对象赋给一个锁对象
    Object lock = this;
    //如果该hashmap不为空
    if (parallelLockMap != null) {
        //产生一把新锁
        Object newLock = new Object();
        //如果该hashmap中存在className的key,则返回key的value,如果不存在,则将className和newLock作为key,value放入hashmap中,返回null
        lock = parallelLockMap.putIfAbsent(className, newLock);
        if (lock == null) {
            lock = newLock;
        }
    }
    return lock;
}

查找最高权限加载器源码

private Class<?> findBootstrapClassOrNull(String name)
{
    if (!checkName(name)) return null;

    return findBootstrapClass(name);
}

// return null if not found
private native Class<?> findBootstrapClass(String name);

findClass源码

protected Class<?> findClass(String name) throws ClassNotFoundException {
    throw new ClassNotFoundException(name);
}

resolveClass源码

protected final void resolveClass(Class<?> c) {
    resolveClass0(c);
}

private native void resolveClass0(Class<?> c);

getResources源码

public Enumeration<URL> getResources(String name) throws IOException {
    //定义一个枚举接口的数组
    @SuppressWarnings("unchecked")
    Enumeration<URL>[] tmp = (Enumeration<URL>[]) new Enumeration<?>[2];
    if (parent != null) {
        //parent为该加载器的双亲,如果双亲对象不为null,使用双亲获取资源
        tmp[0] = parent.getResources(name);
    } else {
        //如果找不到双亲,则获取系统资源
        tmp[0] = getBootstrapResources(name);
    }
    tmp[1] = findResources(name);

    return new CompoundEnumeration<>(tmp);
}
private static Enumeration<URL> getBootstrapResources(String name)
    throws IOException
{
    final Enumeration<Resource> e =
        getBootstrapClassPath().getResources(name);
    return new Enumeration<URL> () {
        public URL nextElement() {
            return e.nextElement().getURL();
        }
        public boolean hasMoreElements() {
            return e.hasMoreElements();
        }
    };
}
protected Enumeration<URL> findResources(String name) throws IOException {
    //返回一个空的枚举集合
    return java.util.Collections.emptyEnumeration();
}

ClassLoader的分类

在标准的Java程序中,Java虚拟机会创建3类ClassLoader为整个应用程序服务。它们分别是:BootStrap ClassLoader(启动类加载器),Extension ClassLoader(扩展类加载器),App ClassLoader(应用类加载器,也称为系统类加载器)。此外,每一个应用程序还可以拥有自定义的ClassLoader,扩展Java虚拟机获取Class数据的能力。其中,应用类加载器的双亲为扩展类加载器,扩展类加载器的双亲为启动类加载器。当系统需要使用一个类时,在判断类是否已经被加载时,会先从当前底层类加载器进行判断。当系统需要加载一个类时,会从顶层类开始加载,依次向下尝试,直到成功。

这里根类加载器即为启动类加载器。通过代码验证

public class PrintClassLoaderTree {
    public static void main(String[] args) {
        ClassLoader cl = PrintClassLoaderTree.class.getClassLoader();
        while (cl != null) {
            System.out.println(cl);
            cl = cl.getParent();
        }
        System.out.println(String.class.getClassLoader());
    }
}

运行结果

sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@4554617c
null

由此可知,PrintClassLoaderTree用户类加载于AppClassLoader中,而AppClassLoader的双亲为ExtClassLoader.而从ExtClassLoader无法再取得启动类加载器,因为这是一个纯C实现。因此,任何加载在启动类加载器中的类时无法获得其ClassLoader实例的,比如String属于Java核心类,因此会被启动类加载器加载,所以最后一条打印为null.

反射的使用场景一般注意以下几点
1、编码阶段不知道需要实例化的类名是哪个,需要在runtime从配置文件中加载:
Class clazz = class.forName("xxx.xxx.xxx")
clazz.newInstance();

2、在runtime阶段,需要临时访问类的某个私有属性
ClassA objA = new ClassA();
Field xxx = objA.getClass().getDeclaredField("xxx")
xxx.setAccessible(true);

3、当使用标签的时候,我们要获取标签
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotionTest {
    String value() default "哈士奇";
}
@AnnotionTest
public class Dog {
    private String type;
    private String name;
    public Dog() {
        type = "金毛";
        name = "大黄";
    }

public class CheckDog {
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.guanjian.Dog");
        if (clazz.isAnnotationPresent(AnnotionTest.class)) {
            Field field = clazz.getDeclaredField("type");
            field.setAccessible(true);
            System.out.println(field.get(clazz.newInstance()));
            AnnotionTest test = (AnnotionTest)clazz.getAnnotation(AnnotionTest.class);
            System.out.println(test.value());
        }
    }
}

4、获取具体的构造器来构造类本身的实例
Class<?>[] constructorParams = {String.class,String.class};
        Constructor<?> cons = clazz.getConstructor(constructorParams);
        System.out.println(cons.newInstance("哈士奇","神哈"));
5、其他(可以用到的地方还有很多,比如获取父类的方法,判断是不是一个接口等等)

因为后面还有一些双亲委托的东西,这个不是我的重点,就不重点写了。重点是结合我之前的一篇文章,做一个解析,见 @Compenent,@Autowired,@PostConstruct自实现

程序主入口

public class Test {
    public static void main(String[] args) {
        Manager.scanAndImp("com.guanjian.test");
        Test2 test2 = (Test2)Manager.getBean(Test2.class);
        test2.show();
    }
}

Manager.scanAndImp("com.guanjian.test")代码如下

public static void scanAndImp(String basePackage) {
    ClassHelper.setClassSet(basePackage);
    BeanHelper.setBeanMap();
    IocHelper.ioc();
}
/**
 * 定义类集合(用于存放所加载的类)
 * @param basePackage
 */
private static  Set<Class<?>> CLASS_SET;

/**
 * 扫描所有的包,获取类集合放入CLASS_SET
 * @param basePackage
 */
public static void setClassSet(String basePackage) {
    CLASS_SET = ClassUtil.getClassSet(basePackage);
}

很明显,第一步是扫描包,获取所有的Class实例,我们根据前面的介绍知道,要装载类,就必须要有一个类装载器,而这个类装载器就是

/**
 * 获取类加载器
 * @return
 */
public static ClassLoader getClassLoader() {
    return Thread.currentThread().getContextClassLoader();
}

因为要装载的类都是我们自己写的类,而不是系统类,所以此时在JVM内存中是肯定没有它们的Class实例的,而装载它们的肯定也就是应用类装载器。

/**
 * 获取制定包名下的所有类
 * @param packageName
 * @return
 */
public static Set<Class<?>> getClassSet(String packageName) {
    ...

代码就不详细分析了,只要知道这里使用了加载器装载了这些类,并产生了Class实例,但并未初始化。其中调用了方法

private static void doAddClass(Set<Class<?>> classSet,String className) {
    Class<?> cls = loadClass(className,false);
    classSet.add(cls);
}
/**
 * 加载类
 * @param className
 * @param isInitialized
 * @return
 */
public static Class<?> loadClass(String className,boolean isInitialized) {
    Class<?> cls;
    try {
        cls = Class.forName(className,isInitialized,getClassLoader());
    } catch (ClassNotFoundException e) {
        LOGGER.error("load class failure",e);
        throw new RuntimeException(e);
    }
    return cls;
}

即为我们之前说的Class.forName()的三参形式。这些所有的Class实例被放入了一个HashSet集合中,即为private static Set<Class<?>> CLASS_SET;

这样第一条语句ClassHelper.setClassSet(basePackage);就分析完了。

--------------------------------------------------------------------------------------------------

然后是第二条语句BeanHelper.setBeanMap();

/**
 * 获取所有Class实例跟类本身实例的映射关系
 */
public static void setBeanMap() {
    Set<Class<?>> beanClassSet = ClassHelper.getBeanClassSet();
    for (Class<?> beanClass:beanClassSet) {
        Object obj = ReflectionUtil.newInstance(beanClass);
        BEAN_MAP.put(beanClass,obj);
    }
}
/**
 * 定义Bean映射(用于存放Bean类与Bean实例的映射关系)
 */
private static final Map<Class<?>,Object> BEAN_MAP = new HashMap<Class<?>, Object>();
/**
 * 获取应用包名下所有Bean类
 * @return
 */
public static Set<Class<?>> getBeanClassSet() {
    Set<Class<?>> beanClassSet = new HashSet<Class<?>>();
    beanClassSet.addAll(getComponentClassSet());
    return beanClassSet;
}
/**
 * 获取应用包名下所有Comonent类
 * @return
 */
public static Set<Class<?>> getComponentClassSet() {
    Set<Class<?>> classSet = new HashSet<Class<?>>();
    for (Class<?> cls:CLASS_SET) {
        //这个Class实例是否带有@Component标签
        if (cls.isAnnotationPresent(Component.class)) {
            classSet.add(cls);
        }
    }
    return classSet;
}
/**
 * 创建实例
 * @param cls
 * @return
 */
public static Object newInstance(Class<?> cls) {
    Object instance;
    try {
        instance = cls.newInstance();
    } catch (Exception e) {
        LOGGER.error("new instance failure",e);
        throw new RuntimeException(e);
    }
    return instance;
}

这里是被@Component标签识别加载的称为bean,我们之前的确获取了所有的类,并且加载了,但并没有初始化。但有一些可能并没有打上@Component标签的就不能称为bean.我们需要对有@Component标签的进行初始化。把bean类跟带有@Component的类分离,是为了方便扩展,以后有其他的标签的可以方便修改。

BeanHelper.setBeanMap();的意思就是把所有的bean都给初始化了,并建立了一个Class实例跟bean类本身的实例的映射关系的HashMap.其中cls.isAnnotationPresent(Component.class)就是检测Class实例是否被我们自定义的标签@Component标记,这是一个比较重点的地方吧。

--------------------------------------------------------------------------------------------------------

然后是第三条语句IocHelper.ioc();

public static void ioc(){
    //获取所有的Bean类与Bean实例之间的映射关系
    Map<Class<?>,Object> beanMap = BeanHelper.getBeanMap();
    if (CollectionUtil.isNotEmpty(beanMap)) {
        //遍历Bean Map
        for (Map.Entry<Class<?>,Object> beanEntry:beanMap.entrySet()) {
            //从BeanMap中获取Bean类与Bean实例
            Class<?> beanClass = beanEntry.getKey();
            Object beanInstance = beanEntry.getValue();
            //获取Bean类定义的所有成员变量
            Field[] beanFields = beanClass.getDeclaredFields();
            if (ArrayUtil.isNotEmpty(beanFields)) {
                //遍历Bean Field
                for (Field beanField:beanFields) {
                    //判断当前Bean Field是否带有Autowired注解
                    if (beanField.isAnnotationPresent(Autowired.class)) {
                        //获取当前Bean Field的Class实例
                        Class<?> beanFieldClass = beanField.getType();
                        //通过该Class实例在HashMap中获取对应的Bean Field类本身的实例,此时并没有设置到Field中
                        //且注意beanFieldInstance是beanInstance某个属性的实例,他们不是同一个实例
                        Object beanFieldInstance = beanMap.get(beanFieldClass);
                        if (beanFieldInstance != null) {
                            //通过反射初始化BeanField的值,把在HashMap中找到的Bean类实例设置给beanInstance
                            //的beanField
                            ReflectionUtil.setField(beanInstance,beanField,beanFieldInstance);
                        }
                    }
                }
            }
            Method[] beanMethods = beanClass.getMethods();
            if (ArrayUtil.isNotEmpty(beanMethods)) {
                //遍历method
                for (Method method:beanMethods) {
                    //判断当前注解是否有PostConstruct注解
                    if (method.isAnnotationPresent(PostConstruct.class)) {
                        try {
                            //执行该方法
                            method.invoke(beanInstance,null);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}
/**
 * 获取Class实例和Bean类本身实例的映射
 * @return
 */
public static Map<Class<?>,Object> getBeanMap() {
    return BEAN_MAP;
}
/**
 * 设置成员变量值
 * @param obj
 * @param field
 * @param value
 */
public static void setField(Object obj, Field field,Object value) {
    try {
        //如果field在类中为private,则必须setAccessible(true)才可以在反射中正常访问
        field.setAccessible(true);
        //obj为要注入的Bean类的实例,value为该Bean类的field字段的要注入的值
        field.set(obj,value);
    } catch (IllegalAccessException e) {
        LOGGER.error("set field failure",e);
        throw new RuntimeException(e);
    }
}

这里主要是为了实现IOC依赖注入(@Autowired标签)以及@PostConstruct标签方法的自动运行。其中Class<?> beanFieldClass = beanField.getType();用来获取类的属性的Class实例,比较重要,再去HashMap中查找该Class实例对应的Bean类本身的实例,这里Class实例跟类本身的实例一定要分清楚。然后ReflectionUtil.setField(beanInstance,beanField,beanFieldInstance);把找到的实例设置给要设置的Bean类的field属性,完成初始化。同样method.invoke(beanInstance,null);也是调用beanInstance自身的方法。

总体思路就是在Class实例中查找各种属性,方法以及类自定义标签、属性自定义标签,方法自定义标签,再结合类本身的实例,通过Class实例的Field,method进行属性赋值,方法运行,这些又都必须在反射(Class实例)中调用类本身的实例。

具体谈一下反射在抽象工厂模式下的应用。

抽象工厂模式下有3个概念,抽象工厂,抽象零件,抽象产品。它是一个以抽象对抽象的处理,无需具体的实现类参与。

具体例子可以参考 设计模式整理

现在我们来看一下反射中比较难理解的几个概念,Type,TypeVariable,Object,Interface

我们还是以例子来说明,假设有两个接口,一个实现类

public interface Greeting<T,V> extends Serializable {
    T sayHello(V name);
    T pay(BigDecimal count);
}
public interface ChildGreeting<T,V> extends Greeting<T,V> {
    T want(String a,V b);
}
public class ChildGreetingImpl implements ChildGreeting<Integer,String> {
    @Override
    public Integer want(String a, String b) {
        return Integer.parseInt(a) + Integer.parseInt(b);
    }

    @Override
    public Integer sayHello(String name) {
        return Integer.parseInt(name);
    }

    @Override
    public Integer pay(BigDecimal count) {
        return count.intValue();
    }
}

我们先用第一个接口来代入这样一段代码

public class TestType {
    public static void main(String[] args) {
        Method[] methods = Greeting.class.getMethods();
        for (Method method : methods) {
            System.out.println(method.getName() + "方法所属类为" + method.getDeclaringClass());
            //如果方法所属类为对象类
            if (method.getDeclaringClass() == Object.class) {
                System.out.println("跳过" + method.getName());
                continue;
            }
            //获取方法的所有参数类型
            Type[] types = method.getGenericParameterTypes();
            for (Type type : types) {
                System.out.println(method.getName() + "参数类型为" + type.getTypeName());
                //如果该参数类型为泛型
                if (type instanceof TypeVariable) {
                    TypeVariable typeVariable = (TypeVariable) type;
                    //获取该参数类型所属的类
                    GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
                    if (genericDeclaration instanceof Class) {
                        Class clazz = (Class) genericDeclaration;
                        System.out.println(method.getName() + "泛型所属类为" + clazz.getName());
                        //如果泛型所属类为接口
                        if (clazz.isInterface()) {
                            //获取接口的父接口
                            Class[] interfaces = clazz.getInterfaces();
                            for (int i = 0;i < interfaces.length;i++) {
                                System.out.println(method.getName() + "父接口包含" + interfaces[i].getName());
                                if (interfaces[i].isAssignableFrom(clazz)) {
                                    System.out.println(interfaces[i].getName() + "为" + clazz.getName() + "的父接口");
                                }
                            }
                            //获取接口的带泛型的父接口类型
                            Type[] genericInterfaces = clazz.getGenericInterfaces();
                            for (int i = 0;i < genericInterfaces.length;i++) {
                                System.out.println(method.getName() + "父接口带泛型名为" + genericInterfaces[i].getTypeName());
                            }

                        }
                    }
                }
            }
        }
    }
}

运行结果

sayHello方法所属类为interface com.guanjian.demo.proxy.Greeting
sayHello参数类型为V
sayHello泛型所属类为com.guanjian.demo.proxy.Greeting
sayHello父接口包含java.io.Serializable
java.io.Serializable为com.guanjian.demo.proxy.Greeting的父接口
sayHello父接口带泛型名为java.io.Serializable
pay方法所属类为interface com.guanjian.demo.proxy.Greeting
pay参数类型为java.math.BigDecimal

这里都没有什么好说的,然后我们来看代入第二个接口

Method[] methods = ChildGreeting.class.getMethods();

其他代码相同,运行结果

want方法所属类为interface com.guanjian.demo.proxy.ChildGreeting
want参数类型为java.lang.String
want参数类型为V
want泛型所属类为com.guanjian.demo.proxy.ChildGreeting
want父接口包含com.guanjian.demo.proxy.Greeting
com.guanjian.demo.proxy.Greeting为com.guanjian.demo.proxy.ChildGreeting的父接口
want父接口带泛型名为com.guanjian.demo.proxy.Greeting<T, V>
sayHello方法所属类为interface com.guanjian.demo.proxy.Greeting
sayHello参数类型为V
sayHello泛型所属类为com.guanjian.demo.proxy.Greeting
sayHello父接口包含java.io.Serializable
java.io.Serializable为com.guanjian.demo.proxy.Greeting的父接口
sayHello父接口带泛型名为java.io.Serializable
pay方法所属类为interface com.guanjian.demo.proxy.Greeting
pay参数类型为java.math.BigDecimal

带入实现类

Method[] methods = ChildGreetingImpl.class.getMethods();

运行结果

want方法所属类为class com.guanjian.demo.proxy.ChildGreetingImpl
want参数类型为java.lang.String
want参数类型为java.lang.Object
want方法所属类为class com.guanjian.demo.proxy.ChildGreetingImpl
want参数类型为java.lang.String
want参数类型为java.lang.String

sayHello方法所属类为class com.guanjian.demo.proxy.ChildGreetingImpl
sayHello参数类型为java.lang.Object
sayHello方法所属类为class com.guanjian.demo.proxy.ChildGreetingImpl
sayHello参数类型为java.lang.String
pay方法所属类为class com.guanjian.demo.proxy.ChildGreetingImpl
pay参数类型为java.math.BigDecimal
pay方法所属类为class com.guanjian.demo.proxy.ChildGreetingImpl
pay参数类型为java.math.BigDecimal
wait方法所属类为class java.lang.Object
跳过wait
wait方法所属类为class java.lang.Object
跳过wait
wait方法所属类为class java.lang.Object
跳过wait
equals方法所属类为class java.lang.Object
跳过equals
toString方法所属类为class java.lang.Object
跳过toString
hashCode方法所属类为class java.lang.Object
跳过hashCode
getClass方法所属类为class java.lang.Object
跳过getClass
notify方法所属类为class java.lang.Object
跳过notify
notifyAll方法所属类为class java.lang.Object
跳过notifyAll

根据结果,但凡实现了带泛型接口的实现类,每一个方法会被一拆而二,一种方法参数类型为Object,一种方法参数为你代入的具体类,所以我们在做某些判断的时候需要注意。

现在我们来修改一下ChildGreeting接口

public interface ChildGreeting<T,V> extends Greeting<T,V> {
    T want(String[] a,V b);
    T findlist(List<String> list);
}

TestType修改如下

public class TestType {
    public static void main(String[] args) {
        Method[] methods = ChildGreeting.class.getMethods();
        for (Method method : methods) {
            System.out.println(method.getName() + "方法所属类为" + method.getDeclaringClass());
            //如果方法所属类为对象类
            if (method.getDeclaringClass() == Object.class) {
                System.out.println("跳过" + method.getName());
                continue;
            }
            //获取方法的所有参数类型
            Type[] types = method.getGenericParameterTypes();
            for (Type type : types) {
                System.out.println(method.getName() + "参数类型名为" + type.getTypeName());
                //如果该参数类型为泛型
                if (type instanceof TypeVariable) {
                    TypeVariable typeVariable = (TypeVariable) type;
                    //获取该参数类型所属的类
                    GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
                    if (genericDeclaration instanceof Class) {
                        Class clazz = (Class) genericDeclaration;
                        System.out.println(method.getName() + "泛型所属类为" + clazz.getName());
                        //如果泛型所属类为接口
                        if (clazz.isInterface()) {
                            //获取接口的父接口
                            Class[] interfaces = clazz.getInterfaces();
                            for (int i = 0;i < interfaces.length;i++) {
                                System.out.println(method.getName() + "父接口包含" + interfaces[i].getName());
                                if (interfaces[i].isAssignableFrom(clazz)) {
                                    System.out.println(interfaces[i].getName() + "为" + clazz.getName() + "的父接口");
                                }
                            }
                            //获取接口的带泛型的父接口类型
                            Type[] genericInterfaces = clazz.getGenericInterfaces();
                            for (int i = 0;i < genericInterfaces.length;i++) {
                                System.out.println(method.getName() + "父接口带泛型名为" + genericInterfaces[i].getTypeName());
                            }

                        }
                    }
                }
                //如果参数类型为Class,且为数组
                if (type instanceof Class && ((Class) type).isArray()) {
                    System.out.println(method.getName() + "数组类型为" + ((Class) type).getComponentType());
                }
                //如果参数类型为参数化类型(参数化类型指类似于List<String>的类型)
                if (type instanceof ParameterizedType) {
                    System.out.println(method.getName() + "参数化类型" + ((ParameterizedType) type).getRawType());
                }

            }
        }
    }
}

运行结果

findlist方法所属类为interface com.guanjian.demo.proxy.ChildGreeting
findlist参数类型名为java.util.List<java.lang.String>
findlist参数化类型interface java.util.List
want方法所属类为interface com.guanjian.demo.proxy.ChildGreeting
want参数类型名为java.lang.String[]
want数组类型为class java.lang.String
want参数类型名为V
want泛型所属类为com.guanjian.demo.proxy.ChildGreeting
want父接口包含com.guanjian.demo.proxy.Greeting
com.guanjian.demo.proxy.Greeting为com.guanjian.demo.proxy.ChildGreeting的父接口
want父接口带泛型名为com.guanjian.demo.proxy.Greeting<T, V>
sayHello方法所属类为interface com.guanjian.demo.proxy.Greeting
sayHello参数类型名为V
sayHello泛型所属类为com.guanjian.demo.proxy.Greeting
sayHello父接口包含java.io.Serializable
java.io.Serializable为com.guanjian.demo.proxy.Greeting的父接口
sayHello父接口带泛型名为java.io.Serializable
pay方法所属类为interface com.guanjian.demo.proxy.Greeting
pay参数类型名为java.math.BigDecimal

由结果可知,参数化类型ParameterizedType,取出来((ParameterizedType) type).getRawType()是一个Class(包含了interface),而数组类型((Class) type).getComponentType()取出来也是一个Class,即数组的原类型。这里需要注意的是,参数化类型ParameterizedType以及泛型TypeVariable都不属于Class,都不能强转成Class,否则都会报错。

再修改ChildGreeting接口

public interface ChildGreeting<T,V> extends Greeting<T,V> {
    T want(String[] a,V[] b);
    T findlist(List<V> list);
}

TestType修改如下

public class TestType {
    public static void main(String[] args) {
        Method[] methods = ChildGreeting.class.getMethods();
        for (Method method : methods) {
            System.out.println(method.getName() + "方法所属类为" + method.getDeclaringClass());
            //如果方法所属类为对象类
            if (method.getDeclaringClass() == Object.class) {
                System.out.println("跳过" + method.getName());
                continue;
            }
            //获取方法的所有参数类型
            Type[] types = method.getGenericParameterTypes();
            for (Type type : types) {
                System.out.println(method.getName() + "参数类型名为" + type.getTypeName());
                //如果该参数类型为泛型
                if (type instanceof TypeVariable) {
                    TypeVariable typeVariable = (TypeVariable) type;
                    //获取该参数类型所属的类
                    GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
                    if (genericDeclaration instanceof Class) {
                        Class clazz = (Class) genericDeclaration;
                        System.out.println(method.getName() + "泛型所属类为" + clazz.getName());
                        //如果泛型所属类为接口
                        if (clazz.isInterface()) {
                            //获取接口的父接口
                            Class[] interfaces = clazz.getInterfaces();
                            for (int i = 0;i < interfaces.length;i++) {
                                System.out.println(method.getName() + "父接口包含" + interfaces[i].getName());
                                if (interfaces[i].isAssignableFrom(clazz)) {
                                    System.out.println(interfaces[i].getName() + "为" + clazz.getName() + "的父接口");
                                }
                            }
                            //获取接口的带泛型的父接口类型
                            Type[] genericInterfaces = clazz.getGenericInterfaces();
                            for (int i = 0;i < genericInterfaces.length;i++) {
                                System.out.println(method.getName() + "父接口带泛型名为" + genericInterfaces[i].getTypeName());
                            }

                        }
                    }
                }
                //如果参数类型为Class,且为数组
                if (type instanceof Class && ((Class) type).isArray()) {
                    System.out.println(method.getName() + "数组类型为" + ((Class) type).getComponentType());
                }
                //如果参数类型为参数化类型(参数化类型指类似于List<String>的类型)
                if (type instanceof ParameterizedType) {
                    System.out.println(method.getName() + "参数化类型" + ((ParameterizedType) type).getRawType());
                }
                //如果参数类型为泛型数组类型
                if (type instanceof GenericArrayType) {
                    System.out.println(method.getName() + "泛型数组类型" + ((GenericArrayType) type).getGenericComponentType());
                }

            }
        }
    }
}

运行结果

findlist方法所属类为interface com.guanjian.demo.proxy.ChildGreeting
findlist参数类型名为java.util.List<V>
findlist参数化类型interface java.util.List
want方法所属类为interface com.guanjian.demo.proxy.ChildGreeting
want参数类型名为java.lang.String[]
want数组类型为class java.lang.String
want参数类型名为V[]
want泛型数组类型V
pay方法所属类为interface com.guanjian.demo.proxy.Greeting
pay参数类型名为java.math.BigDecimal
sayHello方法所属类为interface com.guanjian.demo.proxy.Greeting
sayHello参数类型名为V
sayHello泛型所属类为com.guanjian.demo.proxy.Greeting
sayHello父接口包含java.io.Serializable
java.io.Serializable为com.guanjian.demo.proxy.Greeting的父接口
sayHello父接口带泛型名为java.io.Serializable

由结果可见,泛型数组类型GenericArrayType跟普通数组的判断方式不同,获取方法为((GenericArrayType) type).getGenericComponentType(),获取的也不是一个Class,就是一个泛型。

再修改ChildGreeting接口

public interface ChildGreeting<T,V> extends Greeting<T,V> {
    T want(String[] a,V[] b);
    T findlist(Map.Entry<String,String> entry);
}

TestType修改如下

public class TestType {
    public static void main(String[] args) {
        Method[] methods = ChildGreeting.class.getMethods();
        for (Method method : methods) {
            System.out.println(method.getName() + "方法所属类为" + method.getDeclaringClass());
            //如果方法所属类为对象类
            if (method.getDeclaringClass() == Object.class) {
                System.out.println("跳过" + method.getName());
                continue;
            }
            //获取方法的所有参数类型
            Type[] types = method.getGenericParameterTypes();
            for (Type type : types) {
                System.out.println(method.getName() + "参数类型名为" + type.getTypeName());
                //如果该参数类型为泛型
                if (type instanceof TypeVariable) {
                    TypeVariable typeVariable = (TypeVariable) type;
                    //获取该参数类型所属的类
                    GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
                    if (genericDeclaration instanceof Class) {
                        Class clazz = (Class) genericDeclaration;
                        System.out.println(method.getName() + "泛型所属类为" + clazz.getName());
                        //如果泛型所属类为接口
                        if (clazz.isInterface()) {
                            //获取接口的父接口
                            Class[] interfaces = clazz.getInterfaces();
                            for (int i = 0;i < interfaces.length;i++) {
                                System.out.println(method.getName() + "父接口包含" + interfaces[i].getName());
                                if (interfaces[i].isAssignableFrom(clazz)) {
                                    System.out.println(interfaces[i].getName() + "为" + clazz.getName() + "的父接口");
                                }
                            }
                            //获取接口的带泛型的父接口类型
                            Type[] genericInterfaces = clazz.getGenericInterfaces();
                            for (int i = 0;i < genericInterfaces.length;i++) {
                                System.out.println(method.getName() + "父接口带泛型名为" + genericInterfaces[i].getTypeName());
                            }

                        }
                    }
                }
                //如果参数类型为Class,且为数组
                if (type instanceof Class && ((Class) type).isArray()) {
                    System.out.println(method.getName() + "数组类型为" + ((Class) type).getComponentType());
                }
                //如果参数类型为参数化类型(参数化类型指类似于List<String>的类型)
                if (type instanceof ParameterizedType) {
                    System.out.println(method.getName() + "参数化类型" + ((ParameterizedType) type).getRawType());
                    System.out.println(method.getName() + "参数化所有者类型" + ((ParameterizedType) type).getOwnerType());
                    System.out.println(method.getName() + "参数化各参数类型" + Arrays.toString(((ParameterizedType) type).getActualTypeArguments()));
                }
                //如果参数类型为泛型数组类型
                if (type instanceof GenericArrayType) {
                    System.out.println(method.getName() + "泛型数组类型" + ((GenericArrayType) type).getGenericComponentType());
                }

            }
        }
    }
}

运行结果

findlist方法所属类为interface com.guanjian.demo.proxy.ChildGreeting
findlist参数类型名为java.util.Map$Entry<java.lang.String, java.lang.String>
findlist参数化类型interface java.util.Map$Entry
findlist参数化所有者类型interface java.util.Map
findlist参数化各参数类型[class java.lang.String, class java.lang.String]

want方法所属类为interface com.guanjian.demo.proxy.ChildGreeting
want参数类型名为java.lang.String[]
want数组类型为class java.lang.String
want参数类型名为V[]
want泛型数组类型V
sayHello方法所属类为interface com.guanjian.demo.proxy.Greeting
sayHello参数类型名为V
sayHello泛型所属类为com.guanjian.demo.proxy.Greeting
sayHello父接口包含java.io.Serializable
java.io.Serializable为com.guanjian.demo.proxy.Greeting的父接口
sayHello父接口带泛型名为java.io.Serializable
pay方法所属类为interface com.guanjian.demo.proxy.Greeting
pay参数类型名为java.math.BigDecimal

根据结果可知,如果参数类型为一个类的内部类,这里的类都包含接口,则((ParameterizedType) type).getRawType())会打印内部类,而((ParameterizedType) type).getOwnerType())会打印外部类。((ParameterizedType) type).getActualTypeArguments()会打印所有参数化类型的各个参数类型。

再修改ChildGreeting接口

public interface ChildGreeting<T,V> extends Greeting<T,V> {
    T want(String[] a,V[] b);
    T findlist(Map.Entry<String,String> entry);
    String wide(List<? extends V> list);
}

TestType修改如下

public class TestType {
    public static void main(String[] args) {
        Method[] methods = ChildGreeting.class.getMethods();
        for (Method method : methods) {
            System.out.println(method.getName() + "方法所属类为" + method.getDeclaringClass());
            //如果方法所属类为对象类
            if (method.getDeclaringClass() == Object.class) {
                System.out.println("跳过" + method.getName());
                continue;
            }
            //获取方法的所有参数类型
            Type[] types = method.getGenericParameterTypes();
            for (Type type : types) {
                System.out.println(method.getName() + "参数类型名为" + type.getTypeName());
                //如果该参数类型为泛型
                if (type instanceof TypeVariable) {
                    TypeVariable typeVariable = (TypeVariable) type;
                    //获取该参数类型所属的类
                    GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
                    if (genericDeclaration instanceof Class) {
                        Class clazz = (Class) genericDeclaration;
                        System.out.println(method.getName() + "泛型所属类为" + clazz.getName());
                        //如果泛型所属类为接口
                        if (clazz.isInterface()) {
                            //获取接口的父接口
                            Class[] interfaces = clazz.getInterfaces();
                            for (int i = 0;i < interfaces.length;i++) {
                                System.out.println(method.getName() + "父接口包含" + interfaces[i].getName());
                                if (interfaces[i].isAssignableFrom(clazz)) {
                                    System.out.println(interfaces[i].getName() + "为" + clazz.getName() + "的父接口");
                                }
                            }
                            //获取接口的带泛型的父接口类型
                            Type[] genericInterfaces = clazz.getGenericInterfaces();
                            for (int i = 0;i < genericInterfaces.length;i++) {
                                System.out.println(method.getName() + "父接口带泛型名为" + genericInterfaces[i].getTypeName());
                            }

                        }
                    }
                }
                //如果参数类型为Class,且为数组
                if (type instanceof Class && ((Class) type).isArray()) {
                    System.out.println(method.getName() + "数组类型为" + ((Class) type).getComponentType());
                }
                //如果参数类型为参数化类型(参数化类型指类似于List<String>的类型)
                if (type instanceof ParameterizedType) {
                    System.out.println(method.getName() + "参数化类型" + ((ParameterizedType) type).getRawType());
                    System.out.println(method.getName() + "参数化所有者类型" + ((ParameterizedType) type).getOwnerType());
                    System.out.println(method.getName() + "参数化各参数类型" + Arrays.toString(((ParameterizedType) type).getActualTypeArguments()));
                    Type[] argTypes = ((ParameterizedType) type).getActualTypeArguments();
                    for (Type typeach : argTypes) {
                        //如果该类型为通配符类型(类似于<? extends String>)
                        if (typeach instanceof WildcardType) {
                            if (((WildcardType) typeach).getLowerBounds().length == 1) {
                                System.out.println(method.getName() + "通配符下界类型" + ((WildcardType) typeach).getLowerBounds()[0]);
                            }
                            if (((WildcardType) typeach).getUpperBounds().length == 1) {
                                System.out.println(method.getName() + "通配符上界类型" + ((WildcardType) typeach).getUpperBounds()[0]);
                            }
                        }
                    }
                    System.out.println("克隆前" + argTypes);
                    argTypes = argTypes.clone();
                    System.out.println("克隆后" + argTypes);
                }
                //如果参数类型为泛型数组类型
                if (type instanceof GenericArrayType) {
                    System.out.println(method.getName() + "泛型数组类型" + ((GenericArrayType) type).getGenericComponentType());
                }
            }
        }
    }
}

运行结果

want方法所属类为interface com.guanjian.demo.proxy.ChildGreeting
want参数类型名为java.lang.String[]
want数组类型为class java.lang.String
want参数类型名为V[]
want泛型数组类型V
findlist方法所属类为interface com.guanjian.demo.proxy.ChildGreeting
findlist参数类型名为java.util.Map$Entry<java.lang.String, java.lang.String>
findlist参数化类型interface java.util.Map$Entry
findlist参数化所有者类型interface java.util.Map
findlist参数化各参数类型[class java.lang.String, class java.lang.String]
克隆前[Ljava.lang.reflect.Type;@63961c42
克隆后[Ljava.lang.reflect.Type;@65b54208
wide方法所属类为interface com.guanjian.demo.proxy.ChildGreeting
wide参数类型名为java.util.List<? extends V>
wide参数化类型interface java.util.List
wide参数化所有者类型null
wide参数化各参数类型[? extends V]
wide通配符上界类型V
克隆前[Ljava.lang.reflect.Type;@1be6f5c3
克隆后[Ljava.lang.reflect.Type;@6b884d57

sayHello方法所属类为interface com.guanjian.demo.proxy.Greeting
sayHello参数类型名为V
sayHello泛型所属类为com.guanjian.demo.proxy.Greeting
sayHello父接口包含java.io.Serializable
java.io.Serializable为com.guanjian.demo.proxy.Greeting的父接口
sayHello父接口带泛型名为java.io.Serializable
pay方法所属类为interface com.guanjian.demo.proxy.Greeting
pay参数类型名为java.math.BigDecimal

从结果可知,((WildcardType) typeach).getUpperBounds()[0]可以取到通配符的上界类型,该类型也可能为泛型。另外Type[]数组可以克隆为一个新内存地址的数组。

再修改ChildGreeting接口

public interface ChildGreeting<T,V> extends Greeting<T,V> {
    T want(String[] a,V[] b);
    T findlist(Map.Entry<String,String> entry);
    String wide(List<? super V> list);
}

TestType不变

运行结果

want方法所属类为interface com.guanjian.demo.proxy.ChildGreeting
want参数类型名为java.lang.String[]
want数组类型为class java.lang.String
want参数类型名为V[]
want泛型数组类型V
findlist方法所属类为interface com.guanjian.demo.proxy.ChildGreeting
findlist参数类型名为java.util.Map$Entry<java.lang.String, java.lang.String>
findlist参数化类型interface java.util.Map$Entry
findlist参数化所有者类型interface java.util.Map
findlist参数化各参数类型[class java.lang.String, class java.lang.String]
克隆前[Ljava.lang.reflect.Type;@63961c42
克隆后[Ljava.lang.reflect.Type;@65b54208
wide方法所属类为interface com.guanjian.demo.proxy.ChildGreeting
wide参数类型名为java.util.List<? super V>
wide参数化类型interface java.util.List
wide参数化所有者类型null
wide参数化各参数类型[? super V]
wide通配符下界类型V
wide通配符上界类型class java.lang.Object

克隆前[Ljava.lang.reflect.Type;@1be6f5c3
克隆后[Ljava.lang.reflect.Type;@6b884d57
pay方法所属类为interface com.guanjian.demo.proxy.Greeting
pay参数类型名为java.math.BigDecimal
sayHello方法所属类为interface com.guanjian.demo.proxy.Greeting
sayHello参数类型名为V
sayHello泛型所属类为com.guanjian.demo.proxy.Greeting
sayHello父接口包含java.io.Serializable
java.io.Serializable为com.guanjian.demo.proxy.Greeting的父接口
sayHello父接口带泛型名为java.io.Serializable

由结果可知,<? super V>与<? extends V>不同,<? super V>的下界类型为super后的类型,有上界类型Object。而<? extends V>有上界类型为extands后面的类型,无下界类型。则上下界的划分是以继承方向来确定的,子类为下届,父类为上界。

修改TestType

public class TestType {
    public static void main(String[] args) {
        Method[] methods = ChildGreeting.class.getMethods();
        for (Method method : methods) {
            System.out.println(method.getName() + "方法所属类为" + method.getDeclaringClass());
            //如果方法所属类为对象类
            if (method.getDeclaringClass() == Object.class) {
                System.out.println("跳过" + method.getName());
                continue;
            }
            //获取方法的所有参数类型(Type)
            Type[] types = method.getGenericParameterTypes();
            for (Type type : types) {
                System.out.println(method.getName() + "参数类型名为" + type.getTypeName());
                //如果该参数类型为泛型
                if (type instanceof TypeVariable) {
                    TypeVariable typeVariable = (TypeVariable) type;
                    //获取该参数类型所属的类
                    GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
                    if (genericDeclaration instanceof Class) {
                        Class clazz = (Class) genericDeclaration;
                        System.out.println(method.getName() + "泛型所属类为" + clazz.getName());
                        //如果泛型所属类为接口
                        if (clazz.isInterface()) {
                            //获取接口的父接口
                            Class[] interfaces = clazz.getInterfaces();
                            for (int i = 0;i < interfaces.length;i++) {
                                System.out.println(method.getName() + "父接口包含" + interfaces[i].getName());
                                if (interfaces[i].isAssignableFrom(clazz)) {
                                    System.out.println(interfaces[i].getName() + "为" + clazz.getName() + "的父接口");
                                }
                            }
                            //获取接口的带泛型的父接口类型
                            Type[] genericInterfaces = clazz.getGenericInterfaces();
                            for (int i = 0;i < genericInterfaces.length;i++) {
                                System.out.println(method.getName() + "父接口带泛型名为" + genericInterfaces[i].getTypeName());
                            }

                        }
                    }
                }
                //如果参数类型为Class,且为数组
                if (type instanceof Class && ((Class) type).isArray()) {
                    System.out.println(method.getName() + "数组类型为" + ((Class) type).getComponentType());
                }
                //如果参数类型为参数化类型(参数化类型指类似于List<String>的类型)
                if (type instanceof ParameterizedType) {
                    System.out.println(method.getName() + "参数化类型" + ((ParameterizedType) type).getRawType());
                    System.out.println(method.getName() + "参数化所有者类型" + ((ParameterizedType) type).getOwnerType());
                    System.out.println(method.getName() + "参数化各参数类型" + Arrays.toString(((ParameterizedType) type).getActualTypeArguments()));
                    Type[] argTypes = ((ParameterizedType) type).getActualTypeArguments();
                    for (Type typeach : argTypes) {
                        //如果该类型为通配符类型(类似于<? extends String>)
                        if (typeach instanceof WildcardType) {
                            if (((WildcardType) typeach).getLowerBounds().length == 1) {
                                System.out.println(method.getName() + "通配符下界类型" + ((WildcardType) typeach).getLowerBounds()[0]);
                            }
                            if (((WildcardType) typeach).getUpperBounds().length == 1) {
                                System.out.println(method.getName() + "通配符上界类型" + ((WildcardType) typeach).getUpperBounds()[0]);
                            }
                        }
                    }
                    System.out.println("克隆前" + argTypes);
                    argTypes = argTypes.clone();
                    System.out.println("克隆后" + argTypes);
                }
                //如果参数类型为泛型数组类型
                if (type instanceof GenericArrayType) {
                    System.out.println(method.getName() + "泛型数组类型" + ((GenericArrayType) type).getGenericComponentType());
                }
            }
            //获取方法的参数类(Class)
            Class<?>[] parameterTypes = method.getParameterTypes();
            if (parameterTypes.length > 0) {
                for (Class clazz : parameterTypes) {
                    System.out.println(method.getName() + "参数类为" + clazz.getName());
                }
            }
        }
    }
}

运行结果

want方法所属类为interface com.guanjian.demo.proxy.ChildGreeting
want参数类型名为java.lang.String[]
want数组类型为class java.lang.String
want参数类型名为V[]
want泛型数组类型V
want参数类为[Ljava.lang.String;
want参数类为[Ljava.lang.Object;

findlist方法所属类为interface com.guanjian.demo.proxy.ChildGreeting
findlist参数类型名为java.util.Map$Entry<java.lang.String, java.lang.String>
findlist参数化类型interface java.util.Map$Entry
findlist参数化所有者类型interface java.util.Map
findlist参数化各参数类型[class java.lang.String, class java.lang.String]
克隆前[Ljava.lang.reflect.Type;@63961c42
克隆后[Ljava.lang.reflect.Type;@65b54208
findlist参数类为java.util.Map$Entry
wide方法所属类为interface com.guanjian.demo.proxy.ChildGreeting
wide参数类型名为java.util.List<? extends V>
wide参数化类型interface java.util.List
wide参数化所有者类型null
wide参数化各参数类型[? extends V]
wide通配符上界类型V
克隆前[Ljava.lang.reflect.Type;@1be6f5c3
克隆后[Ljava.lang.reflect.Type;@6b884d57
wide参数类为java.util.List
sayHello方法所属类为interface com.guanjian.demo.proxy.Greeting
sayHello参数类型名为V
sayHello泛型所属类为com.guanjian.demo.proxy.Greeting
sayHello父接口包含java.io.Serializable
java.io.Serializable为com.guanjian.demo.proxy.Greeting的父接口
sayHello父接口带泛型名为java.io.Serializable
sayHello参数类为java.lang.Object
pay方法所属类为interface com.guanjian.demo.proxy.Greeting
pay参数类型名为java.math.BigDecimal
pay参数类为java.math.BigDecimal

由结果可知method.getGenericParameterTypes()method.getParameterTypes()不同,method.getGenericParameterTypes()获取到的泛型,参数化类型,泛型数组类型都是不能直接转化成Class的,但是method.getParameterTypes()获取到的本身就是Class,泛型获取到的Class即为Object.class。参数化类型为集合类型,泛型数组类型为[Ljava.lang.Object;

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部