0%

1-Java反射

前言

这是打算认真写博客后的第一篇,今天来研究一下Java的反射机制。

反射简介

反射机制可以让人们在运行时获得类的信息。

Class类和java.lang.reflect类库(包含Constructor Method Field Modifier Array类)为反射提供了支持。

Class对象

获得Class对象

1
2
3
4
5
6
7
8
9
10
// 第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对象获得(成员/实例/对象)变量。

1
2
3
4
5
6
7
8
9
10
11
// 获得所有(包括父类)的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() // 获得该fieldClass对象
  • setAccessible(Boolean flag) // private的成员变量设置为true后才可访问
  • getModifiers() // 获得该 field的控制符(private static…)对应的整数

方法

获得Method对象

和获得Field对象类似,只要把”Field”改为”Method”。

1
2
3
4
5
6
// 通过方法的参数类型获得
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

简单示例:

1
2
3
4
5
6
7
8
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之后新增的,为ConstructorMethod共用的父类,定义了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