JAVA反射机制
反射机制的概要
JAVA的反射机制,就是可以通过全类名,获取当前类、调用当前类方法,以及获取或修改当前类属性的一个机制。
总结来说:就是通过类对象来获取类信息的一个途径。
如示例:若A类无法引用B类的话,但是又要调用B类的方法,其实就可以调用反射获取B类并且执行B类的方法。
通过反射创建类
首先认识类对象 :Class,类对象中中记录了这个类包含了哪些属性、哪些方法、以及有哪些构造方法等信息。
对于Class的话在这里不多做介绍,具体可以看这个博客:类对象详细介绍.
获取Class的方式
// A的全类名为: package.pojo.A
// 首先有以下几种方式获取类对象
Class a = Class.forName("package.pojo.A"); //参数为类的全类名
Class b = A.class;
Class c = new A().getClass();
获取了 Class 类对象之后,就可以通过类对象去调用方法、获取数据等。
通过Class实例化对象
// 通过Class类对象去实例化对象
try {
// 这里用一种方式去获取Class,也可以用其他方式
Class a = Class.forName("package.pojo.A");
// 通过类对象获取默认构造器
Constructor c = a.getConstructor();
// 通过构造器调用构造方法完成实例化
A a1 = (A)c.newInstance();
// 此时已经获取到A对象,可以通过A对象做后续的事情了
} catch (Exception e) {
e.printStackTrace();
}
通过反射调用类方法
通过Class去调用类的方法的话,应该是我日常中使用反射用的最多的一个方式了,很多时候无法引入类我都会使用反射去调用所需要的类的方法
通过Class获取类中的方法
我们可以通过 getMethod() 获取到Method对象,来调用类方法
当然还有 getDeclaredMethod() 这两个区别请看下面获取属性的方法即可
// 首先请看Class.getMethod()的源码
/**
String name: 需要获取的方法的方法名
Class<?>[] parameterTypes: 调用方法所需的参数的Class数组(可选,无参数则不传递即可)
includeStaticMethods : 是否获取静态方法(可选)
*/
private Method getMethod0(String name, Class<?>[] parameterTypes, boolean includeStaticMethods) {
// 父接口的方法数组
MethodArray interfaceCandidates = new MethodArray(2);
// 获取方法的Method对象
Method res = privateGetMethodRecursive(name, parameterTypes, includeStaticMethods, interfaceCandidates);
// 如果不为空,说明从本类或者父类中获取到了root对象的拷贝对象,直接返回
if (res != null)
return res;
// Not found on class or superclass directly
interfaceCandidates.removeLessSpecifics();
// 如果没从本类/父类中获取到方法,则从父接口中获取方法
return interfaceCandidates.getFirst(); // may be null
}
看完源码之后,其实获取Method对象的就很清晰明了的了,下面是示例
// 首先存在方法为
public String isBigData(String name, Integer number) {
// 省略方法体
}
// 首先肯定要获取相对应的Class对象
Class a = Class.forName("package.pojo.A");
// 通过调用Class.getMethod()获取方法
// 第一个参数为方法名
// 第二个参数为方法所需参数的Class,因为目前是两个参数,所以要传递一个数组如果方法只有一个参数则传递一个参数即可
// 第三个参数,由于当前方法不是Static,不需要传递
Method isBigDataMethod = a.getMethod("isBigData", new Class[] { String.class, int.class });
通过Method调用方法
上面已经学习过了如何通过Class获取Method方法对象,此时就可以通过此方法对象去执行方法了
调用方法主要是用到 Method.invoke() 即可
// Method.invoke()源码如下
/**
由于源码解析太长了就不复制进来了,想要看的可以去看源码里面的介绍,目前针对于参数以及返回值做介绍
* @param obj 调用方法的对象,如调用的是A.isBigData(),此时就传入A对象
* @param args 用于传递给此调用方法的参数,多个就填多个
* @return Object 调用的方法的返回值
*/
@CallerSensitive
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
调用方式如下
// 省略之前步骤,获取Method对象
Method isBigDataMethod = a.getMethod("isBigData", new Class[] { String.class, int.class });
// 由于调用A对象中的方法需要有A对象,所以先创建出来
Class a = Class.forName("package.pojo.A");
Constructor c = a.getConstructor();
Objcet a1 = c.newInstance();
// 直接调用Method.invoke()即可
// 第一个参数调用方法的对象
// 第2,3..个参数,就是调用方法所需的对象
String rtn = isBigDataMethod.invoke(a1, "value1", 3);
// 此时就直接完成了方法的调用了
通过反射修改类属性
通过Class获取属性
Class中存在两个方法可以获取类属性,分别为
Field[] getFields() / Field getField(String name)
Field[] getDeclaredFields() / Field getDeclaredField(String name)
getFields(),只能获取public的属性,无法获取其他属性,Class源码和解释如下
/**
Returns an array containing Field objects reflecting all the accessible public fields of the class or interface represented by this Class object.
If this Class object represents a class or interface with no no accessible public fields, then this method returns an array of length 0.
If this Class object represents a class, then this method returns the public fields of the class and of all its superclasses.
If this Class object represents an interface, then this method returns the fields of the interface and of all its superinterfaces.
If this Class object represents an array type, a primitive type, or void, then this method returns an array of length 0.
The elements in the returned array are not sorted and are not in any particular order.
Returns:
the array of Field objects representing the public fields
*/
// 通过Member.PUBLIC参数来控制只获取public属性
@CallerSensitive
public Field[] getFields() throws SecurityException {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
return copyFields(privateGetPublicFields(null));
}
getDeclaredFields(),则能获取public属性以及private属性,但是不能获取继承的属性
/**
Returns an array of Field objects reflecting all the fields declared by the class or interface represented by this Class object. This includes public, protected, default (package) access, and private fields, but excludes inherited fields.
If this Class object represents a class or interface with no declared fields, then this method returns an array of length 0.
If this Class object represents an array type, a primitive type, or void, then this method returns an array of length 0.
The elements in the returned array are not sorted and are not in any particular order.
Returns:
the array of Field objects representing all the declared fields of this class
*/
@CallerSensitive
public Field[] getDeclaredFields() throws SecurityException {
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
return copyFields(privateGetDeclaredFields(false));
}
则我们可以通过两种方式来获取属性
通过Class修改对象属性
既然都可以将属性获取出来了,此时也可以通过反射对对象设置属性值
// 首先通过反射来获取Class类
Class a = Class.forName("packeage.pojo.A");
// 通过Class实例化一个类
A a = (A) a.getConstructor().newInstance();
// 获取所有属性
Fields fields = a.getFields();
// 可以通过属性名称来获取Field对象
Field attrA = a.getField("属性名称");
// 直接调用Field.set(类对象Object, value)即可修改属性值
attrA.set(a, "value"); // 此时就是给a对象的attrA属性设置值了