1. 简介
Java反射机制是让我们能够在运行期访问和调用类、接口的属性、方法的机制,它通过将上述的类、接口、属性、方法映射成一个个对象来实现,所以,简言之,Java反射机制是使我们能够像操作对象一样来操作上述目标的一种机制。
Java语言的反射机制是强大而实用的,例如,大名鼎鼎的Spring中的IOC底层实现原理就是Java反射机制,由Spring容器创建实例,通过解析xml文件中的id和class等相关属性,创建实例对象,再将它们放入bean容器中。
2. 反射
2.1 类
你可以通过Java的反射机制在运行期获得类的如下信息:
- Class对象
- 类名
- 修饰符
- 包信息
- 父类
- 实现的接口
- 构造器
- 方法
- 属性
- 注解
2.1.1 Class对象
Class对象可以通过Class clazz=Class.forName(className)
,className是一个字符串,表示目标的全类名。获取类全名的方式:Aclass.getName()
,如果不需要全名,那么使用getSimpleNmae()
可以获得不包括包名的简单类名。如果调用Class.forName()
找不到该类,则抛出ClassNotFoundException
。
2.1.2修饰符
即public、private、static之类的关键字
这里修饰符被包装为int类型,这样,每个修饰符都是一个标识位,我们可以通过设置、清除来改变修饰符的类型。int modifiers=clazz.getModifiers();
, java.lang.reflect.Modifier
类设置了大量的方法用来检查修饰符的类型:
Modifier.isAbstract(int modifiers);
Modifier.isFinal(int modifiers);
Modifier.isInterface(int modifiers);
Modifier.isNative(int modifiers);
Modifier.isPrivate(int modifiers);
Modifier.isProtected(int modifiers);
Modifier.isPublic(int modifiers);
Modifier.isStatic(int modifiers);
Modifier.isStrict(int modifiers);
Modifier.isSynchronized(int modifiers);
Modifier.isTransient(int modifiers);
Modifier.isVolatile(int modifiers);
2.1.3 其它信息
- 包信息:
Package package = clazz.getPackage();
- 父类:
Class superclass = clazz.getSuperclass();
- 接口信息:
Class[] interfaces = clazz.getInterfaces();
- 构造器:
Constructor[] constructors = clazz.getConstructors();
- 方法:
Method[] method = clazz.getMethods();
- 属性(变量):
Field[] method = clazz.getFields();
- 注解:
Annotation[] annotations = clazz.getAnnotations();
这里我们需要注意一点,interfaces这个数组中包含的是clazz类显式实现的接口,父类实现的接口是不会被获取的。
2.2 构造器
2.2.1 获取构造器对象
由于一个类可能拥有一个以上的构造器,因此我们获取构造器的方法返回一个公有构造器的数组:Constructor[] constructors = clazz.getConstructors();
。除此之外,我们可以获取指定参数的构造器:Constructor[] constructors = clazz.getConstructors(new Class[]{String.class});
,这里构造方法的参数就是String
类型,如果没有该参数的方法会抛出NoSuchMethodException
。
2.2.2 构造方法参数
我们可以通过Class[] parameterTypes = constructor.getParameterTypes();
来获取指定构造器的方法参数列表。
2.2.3 使用构造器实例化一个类
调用构造器的newInstance()
方法可以实例化一个类对象,该方法返回类型为Object,例如:MyObject myObject = (MyObject)constructor.newInstance(constructor-arg1);
这里newInstance()
方法可以接收一个参数列表,但形参与实参必须一一对应。
2.3 变量(Field)
2.3.1 获取Field对象
上面已经说了一种获取Field数组的方法,现在我们还能够获取指定的Field,如果你知道属性名的话:Field field = clazz.getField("someField");
,如果目标类没有对应属性,那么抛出NoSuchFieldException
。
2.3.2 变量名和变量类型
这两个比较简单:
- 变量名:
String fieldName = field.getName();
- 变量类型:
Object fieldType = field.getType();
2.3.3 Field的set/get方法
通过Field的get与set方法,我们可以轻易地获取改变对象的属性值,
Class clazz= MyObject.class
Field field = clazz.getField("someField");
MyObject objectInstance = new MyObject();
//获取对象的属性,这里如果field是静态变量的话,
//我们就无需传入该类的实例,传入null即可
Object value = field.get(objectInstance);
//设置对象的属性
field.set(objetInstance, value);
2.3 方法(Method)
2.3.1 获取Method对象
前面已经提到了一种获取类的公共的Method列表的方式,现在我们介绍一种可以获得指定Method的方式:
Method method = aClass.getMethod("methodName", new Class[]{String.class});
,这里方法的名称就叫做methodName,方法的参数时String
类型
2.3.2 方法参数及返回类型
- 方法参数类型列表:
Class[] parameterTypes = method.getParameterTypes();
- 方法返回类型:
Class returnType = method.getReturnType();
2.3.3 通过Method对象调用方法
//获取一个方法名为doSomesthing,参数类型为String的方法
Method method = MyObject.class.getMethod("doSomething", String.class);
Object returnValue = method.invoke(null, "parameter-value1");
这里invoke(Object target, Object … parameters)
方法的第一个参数应当是该方法所属类的实例对象,但是此处我们假设该方法时一个静态方法,所以传入null即可,后面是一个参数列表,可以传入多个参数。
//TODO
先写一点基础的,剩下的有空再写