反射

可以通过反射获取应用的任意类和类中的成员, 并且可以执行和设置其值, 需要注意的是反射影响性能, 因为反射是存在于程序运行中才会加载类, 会产生运行堵塞.这也就是动态加载类

动态加载类和静态加载类

  • 动态加载: 即通过字节码加载类, 例Class.forName("xx"), 编译时期类可以不存在, 在运行时期存在即可
  • 静态加载: 即new Clazz()Clazz.method()等方式创建对象或使用静态方法, 此加载方式类必须在编译时期就存在

常见的类:

万物皆对象, 方法和字段等都有对应的类

  • Class 类类型

  • Feild 字段

  • Method 方法

  • Constructor 构造方法

注意:

对于私有的成员必须使用带有Declared方法才能获取到, 这种方法也称为暴力反射, 能获取到任何权限的成员.

获取字节码


读取文件

Class clazz = class.forName("包引用路径");

类名

Class clazz = 类名.class;

对象

Class clazz = 对象名.getClass();

获取对象


Class

  • getName(); 获取类的名字,带包名的
  • getSimpleName(); 获取不带包名的类名
  • newInstance(); 创建空参对象
  • getConstructor(); 获取空参构造方法
  • getConstructor(“”,””,””); 获取有参构造方法
  • getConstructors(); 获取所有的构造方法
  • getDeclaredConstructor(parameterTypes); 获取构造方法
  • getDeclaredConstructor(parameterTypes); 获取全部构造方法

Constructor

  • newInstance(可变参数); 通过参数创建构造方法, 不填参数为空参构造方法
  • getName(); 获取构造方法名称

空参构造方法

1
2
Class clazz = ContactInfo.class;
ContactInfo contactInfo = (ContactInfo)clazz.newInstance();

有参构造方法

1
2
3
// 通过Constructor对象创建有参构造对象
Constructor c = clazz.getConstructor(String.class, int.class);
Person p = (Person) c.newInstance("张三", 23);

获取字段


  • getFields(); 获取所有公有的成员变量
  • getField(“成员变量的名称”); 通过成员变量的名字获取公有的成员变量
  • getDeclaredField(“成员变量的名称”); 通过成员变量的名字获取成员变量
  • getDeclaredFields(); 获取所有的成员变量

Field

  • getType(); 获取字段类型
  • getName(); 获取字段名字
  • set(对象, 参数类类型); 设置字段值
  • setAccessible(true); 给私有的字段设置值之前必须使用此方法设置字段的权限

示例

公有字段

1
2
3
4
// 获取字段
Field f = clazz.getField("字段名");
// 修改字段
f.set(对象名, 值);

私有字段

1
2
3
4
5
6
// 暴力反射获取字段
Field f = clazz.getDeclaredField("字段名");
// 设置字段公开
f.setAccessible(true);
// 修改字段
f.set(对象名, 值);

方法

获取方法

  • getMethod(方法名,参数的类类型); 获取指定公有的方法
  • getDeclaredMethod(); 获取所有的指定的方法
  • getMethods(); 获取所有公有地方法
  • getDelcaredMethods(); 获取类上面所有的方法
  • getParameterType(); 获取参数类型
  • getReturnType(); 获取返回值类型

执行方法

  • invoke(对象, 参数类类型); 执行方法

示例

1
2
3
// 参数无就不填
Method m = clazz.getMethod("方法名", 参数类型.class);
m.invoke(对象名, 参数类类型)