Java反射
什么是反射?
反射就是Reflection,Java的反射是指程序在运行期可以拿到一个对象的所有信息。
获取类
有三个方法,可以获取一个class的Class实例。
- 直接通过
class
的静态变量class
获取: - 通过一个实例变量提供的方法
getClass()
获取 - 知道一个
class
的完整类名,可以通过静态方法Class.forName()
获取
1 | public class Main { |
获取字段
通过class实例获取字段,java中有如下方法
- Field getField(name):根据字段名获取某个public的field(包括父类)
- Field getDeclaredField(name):根据字段名获取当前类的某个field(不包括父类)
- Field[] getFields():获取所有public的field(包括父类)
- Field[] getDeclaredFields():获取当前类的所有field(不包括父类)
1 | public class Main { |
getField()方法可以获取类的publice
方法修饰的成员变量,即使是父类也可以获取,而其余的修饰符则需要使用getDeclaredField()方法获取,该方法可以获取一个类的所有成员变量,但是不能获取到父类的。
获取字段值
要获取字段的值,可以先获取Class
实例,再获取Field
实例,然后,用Field.get(Object)
获取指定实例的指定字段的值。
1 | import java.lang.reflect.Field; |
但是这里我们获取的字段值的修饰符是Public
,那如果是Private
或者Protected
修饰的呢,Protected
修饰的话,仍然可以这样获取道,但如果是Private
修饰的话需要在调用Object value = f.get(p);
前面加上
1 | a.setAccessible(true); |
修改字段值
修改字段值使用的是Field.set(Object, Object)
实现的,其中第一个Object
参数是指定的实例,第二个Object
参数是待修改的值。
1 | import java.lang.reflect.Field; |
获取方法
我们也可以通过Class
实例获取所有Method
信息
和获取字段差不多
Method getMethod(name, Class...)
:获取某个public
的Method
(包括父类)Method getDeclaredMethod(name, Class...)
:获取当前类的某个Method
(不包括父类)Method[] getMethods()
:获取所有public
的Method
(包括父类)Method[] getDeclaredMethods()
:获取当前类的所有Method
(不包括父类)
获取到了Method对象之后一个,就可以进行下一步操作
Method
对象包含一个方法的所有信息:
getName()
:返回方法名称,例如:"getScore"
;getReturnType()
:返回方法返回值类型,也是一个Class实例,例如:String.class
;getParameterTypes()
:返回方法的参数类型,是一个Class数组,例如:{String.class, int.class}
;getModifiers()
:返回方法的修饰符,它是一个int
,不同的bit表示不同的含义。public
是1,privat
e是2,protected
是4。
1 | import java.lang.reflect.Method; |
调用方法
调用方法需要先获取方法,然后调用invoke
,调用invoke
就相当于调用该方法,invoke
的第一个参数是对象实例,即在哪个实例上调用该方法,后面的可变参数要与方法参数一致,否则将报错。
以上面那个例子
1 | import java.lang.reflect.Method; |
和Field类似,对于非public方法,我们虽然可以通过Class.getDeclaredMethod()
获取该方法实例,但直接对其调用将得到一个IllegalAccessException
。为了调用非public方法,我们通过Method.setAccessible(true)
允许其调用。
调用构造方法
如果通过反射来创建新的实例,可以调用Class提供的newInstance()方法:
1 | Person p = Person.class.newInstance(); |
调用Class.newInstance()的局限是,它只能调用该类的public无参数构造方法,如果要调用有参构造方法,或者构造函数是非Public
的就需要使用下面的这些。
通过Class实例获取Constructor的方法如下:
getConstructor(Class...)
:获取某个public
的Constructor
;getDeclaredConstructor(Class...)
:获取某个Constructor
;getConstructors()
:获取所有public
的Constructor
;getDeclaredConstructors()
:获取所有Constructor
。
Constructor
总是当前类定义的构造方法,和父类无关,因此不存在多态的问题。
调用非public
的Constructor
时,必须首先通过setAccessible(true)
设置允许访问。setAccessible(true)
可能会失败。
参考自:https://www.liaoxuefeng.com/wiki/1252599548343744/1255945147512512