前言
这是打算认真写博客后的第一篇,今天来研究一下Java的反射机制。
反射简介
反射机制可以让人们在运行时获得类的信息。
Class
类和java.lang.reflect
类库(包含Constructor
Method
Field
Modifier
Array
类)为反射提供了支持。
Class
对象
获得Class
对象
// 第1种方法
Class clazz0 = String.class;
// 第2种方法
Example example = new Example();
Class clazz1 = example.getClass();
// 第3种方法
// ! java.lang.ClassNotFoundException
Class clazz2 = Class.forName("com.example.Example");
Class
对象相关操作
部分方法:
从名字就大概知道作用了。
getPackage()
getName()
getSuperClass()
getInterface()
getModifier()
getConstructors()
getMethods()
getFields()
getAnnotations()
getClasses()
// 获得内部类getDeclaringClass()
// 如果该类为内部类,获得对应外部类,否则返回null
- …
没有
setAccessible(...)
完整方法见Java 文档
解析Modifier
类
常用静态方法:
isPublic(int mod)
- …
- …
isStatic(int mod)
isFinal(int mod)
toString(int mod)
// 以字符串的形式返回所有修饰符
变量
获得Field
对象
通过上面获得的Class
对象获得(成员/实例/对象)变量。
// 获得所有(包括父类)的public的成员变量
Field[] fields1 = clazz.getFields();
// 获得指定名称的成员变量
Field field1 = clazz.getField("mField");
// 获得所有权限(不包括父类)的成员变量
Field[] fields2 = clazz.getDeclaredFields();
// 获得指定名称的成员变量
Field field2 = clazz.getDeclaredField("mField");
Field
对象相关操作
部分方法:
set(Object obj, Object value)
getBoolean(Object obj)
setBoolean(Object obj, boolean z)
// 通过此方法设置field
的值- …
getName()
getType()
// 获得该field
的Class
对象setAccessible(Boolean flag)
//private
的成员变量设置为true
后才可访问getModifiers()
// 获得该field
的控制符(private
static
…)对应的整数
方法
获得Method
对象
和获得Field
对象类似,只要把”Field”改为”Method”。
// 通过方法的参数类型获得
Method method = clazz.getMethod(String.class,int.class);
// 或
Method method = clazz.getMethod(new Class[]{String.class, int.class})
// getDeclaredMethod(Class<?> parameterTypes)同上
Method对象相关操作
部分方法:
getName()
getParameterTypes()
// 返回值Class[]
形式getReturnType()
getExceptionTypes()
isVarArgs()
// 是否是可变参数类型getModifier()
setAccessible(Boolean flag)
invoke(Object obj, Object... args)
// 调用obj
的此方法,args
为参数
构造方法
获得Constructor
对象
和获得Method
对象类似,只要把”Method”改为”Constructor”。
Constructor
对象相关操作
部分方法:
newInstance(Object... initargs)
// 通过指定参数创建类的实例,参数未设置则采用默认构造方法
其他和Method
一样。
操作私有变量和私有方法
我们都知道是无法直接对私有变量和私有方法进行操作的,但通过反射,即先用getDeclaredXXX()
获得所有权限(不包括父类)的XXX
,再setAccessible(true)
就可以操作了。
使用Array
简单示例:
Class cls = Class.forName("java.lang.String");
// 创建10个类型为cls的对象
// 还可以传入可变参数为维度
Object arr = Array.newInstance(cls, 10);
// 设置第5个对象的内容
Array.set(arr, 5, "this is a test");
String s = (String)Array.get(arr, 5);
System.out.println(s);
Executable
1.8之后新增的,为Constructor
和Method
共用的父类,定义了TA们共有的功能。
getParameters()
- …
Parameter
1.8之后新增的,保存了关于方法参数的信息。
反射效率
后记
修改常量
常量在Java中用final
修饰。而为了提高执行效率,编译器在把.java
文件编译成.class
文件时,一般会把int
long
boolean
等基本数据类型和String
类的常量替换成对应的常量值。Java虚拟机执行的是.class
文件,所以在程序执行时编码中常量的使用位置已经是直接的值了。因此虽然常量值可以被修改,但已经没有TA发挥作用的位置了。
其实仍要修改还是有可能的,那就是常量没有被换成值的情况~~,但貌似比较傻~~。
情况举例:
-
// 常量通过如下方法赋值 private final String FINAL_VALUE = null == null ? "FINAL" : null;
-
final
常量在构造函数中赋值。
参考了这篇文章
反射的有趣应用
可以看下这篇文章,不过new Integer(1)
已经被废弃了,可以用setInt(Object obj, int i)
代替set()
。
完。
2019-10-13 18:28:56