反射离不开Class.forName(),咱们先从Class.forName提及。java
上一篇咱们说要获得一个类的实例有4个方法:new,反射,克隆,反序列化。bootstrap
反射能够跟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'}jvm
又能够写成以下ide
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'}this
虽然效果同样,但他们的过程并不同。 首先,newInstance( )是一个方法,而new是一个关键字;其次,Class下的newInstance()的使用有局限,由于它生成对象只能调用无参的构造函数,而使用 new关键字生成对象没有这个限制。编码
newInstance()的时候是使用的上篇说的类装载机制的,它会走彻底部过程。具体能够看 浅析类装载 ,而new一个实例的时候,走的流程不太同样,它会先在JVM内部先去寻找该类的Class实例,而后依照该Class实例的定义,依葫芦画瓢,把该类的实例给生成出来。但若是找不到该类的Class实例,则会走上篇说的装载流程。 其中JDK的Class实例通常是在jvm启动时用启动类加载器完成加载,用户的Class实例则是在用到的时候再加载。spa
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 loader 和 extension 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);
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.
反射的使用场景通常注意如下几点
一、编码阶段不知道须要实例化的类名是哪一个,须要在runtime从配置文件中加载:
Class clazz = class.forName("xxx.xxx.xxx")
clazz.newInstance();
二、在runtime阶段,须要临时访问类的某个私有属性
ClassA objA = new ClassA();
Field xxx = objA.getClass().getDeclaredField("xxx")
xxx.setAccessible(true);
三、当使用标签的时候,咱们要获取标签
@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());
}
}
}
四、获取具体的构造器来构造类自己的实例
Class<?>[] constructorParams = {String.class,String.class};
Constructor<?> cons = clazz.getConstructor(constructorParams);
System.out.println(cons.newInstance("哈士奇","神哈"));
五、其余(能够用到的地方还有不少,好比获取父类的方法,判断是否是一个接口等等)
由于后面还有一些双亲委托的东西,这个不是个人重点,就不重点写了。重点是结合我以前的一篇文章,作一个解析,见 @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后面的类型,无下界类型。则上下界的划分是以继承方向来肯定的,子类为下届,父类为上界。