1. 反射
反射这个名词似乎很难理解,但是实际上就是通过另一种方式去操作对象而已。
一般操作对象是直接通过对象引用,比如A a = new A();
通过引用a来操作相应的那个对象。
但是如果对象引用是父类类型,或者干脆是Object,就需要找出这个对象的真正类型。例如object o = new A();
这个定义是合法的,但是通过引用o没法调用真正的A包含的特有属性和方法,所以反射就是通过o去内存中获取A类的相关信息(有哪些字段,有哪些方法),然后通过相应的属性名和方法名去操作o,就可以像正常使用一样去进行编程(当然不是直接通过a.xxx来调用)。
想象这样一个场景,我定义一个方法,传入参数我想设计为Man或者Woman,二者具有不同的属性和方法,并且都继承People类,那么传入参数就是People p了,运用反射我就可以判断出这个p是Man还是Woman,继而进行相应的操作。
2. 类对象
那么,如何从内存中获取目标类A的信息呢?直接解析new A产生的对象本身?也许可以,但是有更简便的办法。
Class类 是一个 Java 类,保存的是与之对应 Java 类的 meta信息(元信息),用来描述这个类的结构,比如描述一个类有哪些成员,有哪些方法等,一般在反射中使用。Class类就是“类的类”,是用来记录类信息的一种类。类对象(Class对象)就是目标类在内存中产生的Class类的实例。
我们想要进行操作的目标是A类,在加载A类的时候,内存会根据A类产生一个Class对象,专门用来记录A类的信息(有哪些成员,有哪些方法等),想获取A的类信息时,只需要获取这个A类的Class对象即可。
3. 获取类对象的方法
-
通过对象获取
在持有一个对象的时候,可以直接调用getClass方法得到类对象。
对象.getClass()
-
通过类名直接获取
类.class
-
通过类名字符串获取
一般在使用连接数据库的时候最常用到,
Class.forName("类名字符串")
.这个方法和前一种很像,一般情况下使用前一种就行了,使用这种方法需要结合类加载机制的知识,不过多深究。
4. 类对象的操作
这里主要是记一下如何通过Class对象来进一步获取类的相关信息。一个类有成员与方法,这二者的信息会被存储在它对应的Class里面,类的成员变量在类对象中以Field类的形式存在,方法变量在类对象中则以Method类的形式存在,二者都继承了AnnotatedElement接口。
可以理解为,Class类里面维护两个列表,一个是Field实例的列表,一个是Method实例的列表。
Field
-
获取Field
类的成员变量在类对象中以Field对象的形式存在,以下方法可获取相关Field
getField(String name) --根据某属性名字符串获取该字段
getDeclaredField(String name) --无视修饰符根据某属性名字符串获取该字段
getDeclaredFields() --获取所有字段
getDeclaredFields() --无视修饰符获取所有字段
-
Field的操作
setAccessible(boolean flag) --值未true可以强制设置是否可以访问
getName() --获取字段名称
get(Object obj) --获取目标类某实例obj在本字段的值。
set(Object obj, Object value) --设置目标类某实例obj在本字段上的值
Method
类的方法变量在类对象中则以Method对象的形式存在
-
获取Method
getMethod(String name, Class<?>… parameterTypes) --获取类的某方法,第一个参数填方法名,后续参数顺序填写该方法的参数
getMethod(String name) --根据方法名称符串获取该方法getDeclaredMethod() --无视修饰符根据某方法名字符串获取该方法
getDeclaredMethods() --获取所有方法
getDeclaredMethods() --无视修饰符获取所有方法
-
Method的操作
setAccessible(boolean flag) --值未true可以强制设置是否可以访问
getName() --获取方法名称
invoke(Object obj, Object… args) --调用该方法,第一个参数填写目标类的实例,其余参数填写该方法需要的参数
Annotation
Class类里面还有个Annotation来记录目标类的注解,在自定义注解的时候必须用到。
填坑wait…