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)时无法通过上述方法获取,需使用 getDeclaredFields
或getDeclaredField
获取目标私有成员变量
直接获取私有变量会提示权限不够
Field field = personClass.getDeclaredField("Name");
System.out.println(field.get(person));
访问私有成员变量时需要将setAccessible设置为true,关闭安全检查后才可获取私有成员变量内容
注:getDeclaredFields
或getDeclaredField
并不是只用来获取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");
获取私有有参构造方法
Class personClass = Class.forName("Person");
Constructor constructor = personClass.getDeclaredConstructor(String.class,String.class);
constructor.setAccessible(true);//同样也需要关闭安全检查
Person person = (Person) constructor.newInstance("p1","p2");
获取对象公共、私有方法
获取对象公共方法
Class personClass = Class.forName("Person");
Person person = (Person) personClass.newInstance();
Method method = personClass.getMethod("ThisPublic");
method.invoke(person);
获取对象私有方法
Class personClass = Class.forName("Person");
Person person = (Person) personClass.newInstance();
Method method = personClass.getDeclaredMethod("ThisPrivate");
method.setAccessible(true);
method.invoke(person);
利用反射执行命令
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");
或使用更简短的方法来实现命令执行
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");