Java基础 反射

了解JAVA反射

Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。

JAVA反射原理

获取Class对象然后使用java.lang.reflect里提供的方法操作Class对象,Class与java.lang.reflect构成了java的反射技术

JAVA反射关键的包和类

Class类

  • forName方法可以根据类的完全限定名称获取Class对象。会加载和连接,根据initialize参数决定是否初始化。(我们常用的不指定initialize就是默认初始化)
  • newInstance 创建此Class对象表示的类的新实例 内部实现是调用的Constructor.newInstance方法
  • getClasses 获取在此Class对象对应的类型中声明的public类或接口成员的Class对象数组,包括从超类继承的public类和接口成员
  • getDeclaredClasses 获取在此Class对象对应的类型中声明的类或接口成员的Class对象数组,包括public, protected, default (package) access,private类和接口,但不包括继承的类和接口
  • getFields 获取此Class对象表示的类或接口的所有可访问public字段Field数组 包括继承的
  • getDeclaredFields 获取此Class对象表示的类或接口的所有 public、protected、default(package)access和private字段Field数组 不包括继承的
  • getField 获取此Class对象表示的类或接口的指定的可访问public字段Field对象 会递归向父类、父接口查
  • getDeclaredField 获取此Class对象表示的类或接口的指定的public、protected、default(package)access和private字段Field对象 不包括继承的
  • getMethods 获取该class对象表示的类或接口的所有public方法Method数组 包括继承的
  • getDeclaredMethods 获取该class对象表示的类或接口的public, protected, default (package) access,private方法Method数组 不包括继承的
  • getMethod 获取该class对象表示的类或接口的指定的public方法Method数组 会递归向父类、父接口查
  • getDeclaredMethod 获取该class对象表示的类或接口的指定的public方法Method数组 不包括继承的
  • getConstructors 获取这个class对象表示的类的所有public构造函数Constructor数组
  • getDeclaredConstructors 获取这个class对象表示的类的所有public、protected、default(package)access和private 构造函数Constructor数组
  • getConstructor 获取这个class对象表示的类的指定的public构造函数Constructor对象
  • getDeclaredConstructor 获取这个class对象表示的类的指定的public、protected、default(package)access和private 构造函数Constructor对象

Reflect包下的关键类

Constructor

获取Class对象中的构造方法

  • getConstructor 获取当前类或父类单个公共构造方法
  • getConstructors 获取当前类或父类所有公共构造方法
  • getDeclaredConstructor 获取当前类单个构造方法
  • getDeclaredConstructors 获取当前类所有构造方法

Method

获取Class对象中的方法

  • getMethod 获取当前类或父类单个公共方法
  • getMethods 获取当前类或父类所有公共方法
  • getDeclaredMethod 获取当前类单个方法
  • getDeclaredMethods 获取当前类所有方法
  • invoke 执行指定对象 obj 中的Method

Field

获取Class对象中的成员属性

  • getField 获取单个当前类或父类的public变量
  • getFields 获取当前类或父类的所有public变量
  • getDeclaredField 获取单个当前类的public、private、protected变量
  • getDeclaredFields 获取所有当前类的public、private、protected变量

JAVA反射实现及利用

获取Class对象

利用New获取目标对象

Person person = new Person();
Class targetClass = person.getClass();

利用.class获取目标对象

Class personClass = Person.class;

利用Class.forName获取目标对象

Class targetClass = Class.forName("Person");

利用loadClass获取目标对象

this.getClass().getClassLoader().loadClass("Person");

获取Class属性

获取对象实例

获取对象后可利用newInstance()将对象进行实例化

注:Class.newInstance只能用来构造无参构造函数与后面提到的Constructor.newInstance有很大区别

Class personClass = Class.forName("Person");
Person person = (Person) person_class.newInstance();

获取对象成员变量

获取公有变量

获取单个公有变量

person_class.getField("addr")

获取所有公有变量:getFields()

Field[] fields = person_class.getFields();
for(Field field:fields){
    System.out.println(field.getName());
}

获取私有变量

当目标成员变量为私有变量(private)时无法通过上述方法获取,需使用 getDeclaredFieldsgetDeclaredField获取目标私有成员变量

直接获取私有变量会提示权限不够

Field field = personClass.getDeclaredField("Name");
System.out.println(field.get(person));

image.png

访问私有成员变量时需要将setAccessible设置为true,关闭安全检查后才可获取私有成员变量内容

image.png

注:getDeclaredFieldsgetDeclaredField并不是只用来获取private变量,public变量同样也获取到

getDeclaredField和getField区别

  • getDeclaredField只可获取类本身 public private protected成员属性
  • getField可获取类本身及父类的public成员属性

获取对象成员方法

获取对象构造方法

在前面获取Class属性-获取对象实例时提到过,利用newInstance只能用来构造无参构造函数,在这里说一下如何构造私有、公有及有参构造函数

获取有参构造方法
Class personClass = Class.forName("Person");
Constructor constructor =  personClass.getConstructor(String.class);
Person person = (Person) constructor.newInstance("param");

image.png

获取私有有参构造方法
Class personClass = Class.forName("Person");
Constructor constructor =  personClass.getDeclaredConstructor(String.class,String.class);
constructor.setAccessible(true);//同样也需要关闭安全检查
Person person = (Person) constructor.newInstance("p1","p2");

image.png

获取对象公共、私有方法

获取对象公共方法
Class personClass = Class.forName("Person");
Person person = (Person) personClass.newInstance();
Method method = personClass.getMethod("ThisPublic");
method.invoke(person);

image.png

获取对象私有方法
Class personClass = Class.forName("Person");
Person person = (Person) personClass.newInstance();
Method method = personClass.getDeclaredMethod("ThisPrivate");
method.setAccessible(true);
method.invoke(person);

image.png

利用反射执行命令

Class RuntimeClass = Class.forName("java.lang.Runtime");
Constructor constructor = RuntimeClass.getDeclaredConstructor();
constructor.setAccessible(true);
constructor.newInstance();
Runtime runtime = (Runtime) constructor.newInstance();
runtime.exec("open /System/Applications/Calculator.app");

image.png

或使用更简短的方法来实现命令执行

Class.forName("java.lang.Runtime").getMethod("exec",String.class).invoke(Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime")),"open /System/Applications/Calculator.app");

image.png

-->