概念
反射是Java的特征之一,是一种间接操作目标对象的机制
在JVM运行的时候会动态加载类,对于任意一个类都能获取到该类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就是Java的反射机制
阅读建议:
- 如果您是Java反射机制的初学者,我觉得应该优先阅读示例和反射常用API
反射机制
Java类在执行过程中的变化如下(借大佬的图一用
过程我是这样理解的:
Class类文件 ⇒ Class类字节码文件 ⇒ Class类对象 ⇒ Class类对象实例
在类加载器去加载一个类的时候,反射机制允许程序在执行期间借助ReflectionAPI取得任意类的内部信息(属性,方法),并能操作对象的属性及方法。
在加载完成后,在堆中就会产生一个Class类对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。
在运行时Java反射机制可以完成:
- 判断任意一个对象所属的类
- 构造任意类的对象
- 得到任意类所具有的属性和方法
- 调用任意一个对象的属性和方法
- 动态代理
反射相关的主要类:
- Java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象
- Java.lang.reflect.Method:代表类的方法
- Java.lang.reflect.Field:代表类的成员变量
- Java.lang.reflect.Constructor:代表类的构造方法
示例
在使用Java反射之前,我们先来构造一个类User.java
package com.reflect;
public class User {
public String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public void Hello() {
System.out.println(this.name + "'s age is " + this.age + "!");
}
}
先按照正常思路去实现一个User类
对象并调用Hello方法
,再写一个Normal.java
package com.reflect;
public class Normal {
public static void main(String[] args) {
User user = new User("xiaoming", 18);
user.Hello();
}
}
然后我们再使用反射的方式去实现User类
对象并调用Hello方法
,写一个Reflect.java
package com.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Reflect {
public static void main(String[] args) throws Exception{
Class clazz = Class.forName("com.reflect.User");
Constructor constructor = clazz.getConstructor(String.class, int.class);
Object xiaogao = constructor.newInstance("xiaogao", 18);
Method hello = clazz.getMethod("Hello");
hello.invoke(xiaogao);
}
}
先来简单理解一下上述代码,在阅读过反射常用API后将有进一步的认识:
-
通过
Class.forName
方法获取指定的Class类对象通过
getConstructor方法
获得类对象的构造器通过
newInstance方法
获得类对象实例通过
getMethod方法
获得类对象的方法通过
invoke方法
执行该类对象实例的该方法
反射常用API
Class类对象的获取
类的class属性
package com.reflect;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class clazz = User.class;
System.out.println(clazz);
}
}
// OUT:class com.reflect.User
这种方法是一种比较简单的方法,只需要知道Class的名称就可以
实例化对象的getClass()方法
package com.reflect;
public class ReflectClass {
public static void main(String[] args) throws Exception{
User xiaojun = new User("xiaojun", 18);
Class clazz = xiaojun.getClass();
System.out.println(clazz);
}
}
// OUT:class com.reflect.User
这种方法是先获得了类对象实例然后获得Class类对象,所以用的比较少
Class.forName(String className)方法:动态加载类
package com.reflect;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class clazz = Class.forName("com.reflect.User");
System.out.println(clazz);
}
}
// OUT:class com.reflect.User
构造方法Constructor的获取
User类
新增构造方法
public User() {
this.name = "";
this.age = 0;
}
protected User(String name) {
this.name = name;
this.age = 0;
}
getConstructors():返回public构造方法
返回了User类所有的public
构造方法
package com.reflect;
import java.lang.reflect.Constructor;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class clazz = User.class;
Constructor[] constructors = clazz.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
}
}
// OUT:
// public com.reflect.User()
// public com.reflect.User(java.lang.String,int)
getConstructor(Class<?>…parameterTypes):返回匹配参数类型的public构造方法
返回了指定了参数类型的public
构造方法
package com.reflect;
import java.lang.reflect.Constructor;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class clazz = User.class;
Constructor xiaoming = clazz.getConstructor(String.class, int.class);
System.out.println(xiaoming);
}
}
// OUT:public com.reflect.User(java.lang.String,int)
getDeclaredConstructors():返回所有的构造方法
返回了所有的构造方法
package com.reflect;
import java.lang.reflect.Constructor;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class clazz = User.class;
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
}
}
// OUT:
// public com.reflect.User()
// public com.reflect.User(java.lang.String,int)
// protected com.reflect.User(java.lang.String)
getDeclaredConstructor(Class<?>…parameterTypes):返回匹配参数类型的构造方法
返回了指定了参数类型的构造方法
package com.reflect;
import java.lang.reflect.Constructor;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class clazz = User.class;
Constructor xiaoming = clazz.getDeclaredConstructor(String.class);
System.out.println(xiaoming);
}
}
// OUT:protected com.reflect.User(java.lang.String)
对象实例的获取
通过Class对象的newInstance()方法
通过该种方法只能获得Class对象的无参构造方法并创建对象实例
package com.reflect;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class clazz = User.class;
User user = (User)clazz.newInstance();
user.Hello();
}
}
// OUT:'s age is 0!
通过Constructor对象的newInstance()方法
通过getConstructor()
方法获取Constructor
对象可以获取到Class对象的特定构造方法,并创建对象实例
package com.reflect;
import java.lang.reflect.Constructor;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class clazz = User.class;
Constructor xiaoming = clazz.getConstructor(String.class, int.class);
User user = (User)xiaoming.newInstance("xiaoming", 20);
user.Hello();
}
}
// OUT:xiaoming's age is 20!
成员变量Field的获取
getFields():获取所有public修饰的成员变量
package com.reflect;
import java.lang.reflect.Field;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class clazz = User.class;
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field);
}
}
}
// OUT:public java.lang.String com.reflect.User.name
getField(String name):获取指定名称的public修饰的成员变量
package com.reflect;
import java.lang.reflect.Field;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class clazz = User.class;
Field name = clazz.getField("name");
System.out.println(name);
}
}
// OUT:public java.lang.String com.reflect.User.name
getDeclaredFields():获取所有的成员变量
package com.reflect;
import java.lang.reflect.Field;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class clazz = User.class;
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
}
}
// OUT:
// public java.lang.String com.reflect.User.name
// private int com.reflect.User.age
getDeclaredField():获取指定的成员变量
package com.reflect;
import java.lang.reflect.Field;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class clazz = User.class;
Field name = clazz.getDeclaredField("age");
System.out.println(name);
}
}
// OUT:private int com.reflect.User.age
成员方法Method的获取
User类
新增方法
public void Hello(int age) {
System.out.println(this.name + "'s age is " + age + "!");
}
private void Hi(String name) {
System.out.println(name + "'s age is " + this.age + "!");
}
getMethods():获取所有的public方法
获取包括自身和父类声明的public方法,以及实现的接口方法
package com.reflect;
import java.lang.reflect.Method;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class clazz = User.class;
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
getMethod(String name, Class<?>…parameterTypes):获取指定名称的public方法
第一个参数为该public方法的名称,第二个参数为该方法的参数类型
package com.reflect;
import java.lang.reflect.Method;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class clazz = User.class;
Method hello = clazz.getMethod("Hello", int.class);
System.out.println(hello);
}
}
getDeclaredMethods():获取所有方法
仅仅只是获取该类所声明的所有方法(不包括父类以及实现的接口方法)
package com.reflect;
import java.lang.reflect.Method;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class clazz = User.class;
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
getDeclaredMethod(String name, Class<?>…parameterTypes):获取指定名称的方法
package com.reflect;
import java.lang.reflect.Method;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class clazz = User.class;
Method hello = clazz.getDeclaredMethod("Hi", String.class);
System.out.println(hello);
}
}
invoke方法执行对象的目标方法
invoke方法位于java.lang.reflect.Method类中,用于执行某个对象的目标方法
public Object invoke(Object obj, Object... args)
第一个参数为类的实例,第二个参数为相应函数中的参数
User类
新增静态方法
public static void Bye(String name, int age) {
System.out.println(name + "'s age is " + age + "!");
}
如果调用的目标方法是普通方法,第一个参数是Class对象实例
package com.reflect;
import java.lang.reflect.Method;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class clazz = User.class; // 获取Class对象
User user = (User)clazz.newInstance(); // 获取Class对象实例
Method hello = clazz.getMethod("Hello", int.class); // 获取Hello(int age)怕普通方法
hello.invoke(user, 20); // 执行方法并传入参数
}
}
如果调用的目标方法是静态方法,第一个参数就是Class对象(这里还可以使用null空置该参数,也可以执行当前Class对象的方法)
package com.reflect;
import java.lang.reflect.Method;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class clazz = User.class; // 获取Class对象
Method hello = clazz.getMethod("Bye", String.class, int.class); // 获取Bye(String name, int age)静态方法
hello.invoke(clazz, "xiaomei", 20); // 这里的第一个参数为Class对象
}
}
通过反射构造Runtime类执行
我们先来正常使用Runtime类执行一条命令并弹出计算器
package com.reflect;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Runtime.getRuntime().exec("calc");
}
}
接下来我们通过反射的方式来执行命令
package com.reflect;
import java.lang.reflect.Method;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class clazz = Class.forName("java.lang.Runtime");
Object o = clazz.newInstance();
Method getRuntime = clazz.getMethod("getRuntime");
Method exec = clazz.getMethod("exec", String.class);
exec.invoke(getRuntime.invoke(clazz), "calc");
}
}
我们先通过forName
方法获取Runtime
类对象,然后再通过newInstance
方法创造实例,结果发现在newInstance
这里报了错!
经过读报错和查询我们发现Runtime类的构造方法是private权限的
当使用的类构造函数不是public的,或者没有无参构造函数的话,是不可以用newInstance方法直接创造实例的
通过查看getRuntime方法,发现该方法为静态方法,所以我们并不需要创建实例也可以执行该方法
故我们修改代码如下:
package com.reflect;
import java.lang.reflect.Method;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class clazz = Class.forName("java.lang.Runtime");
Method getRuntime = clazz.getMethod("getRuntime");
Method exec = clazz.getMethod("exec", String.class);
exec.invoke(getRuntime.invoke(clazz), "calc");
}
}
我们先获得Runtime
对象的exec
方法和Runtime
方法,然后通过Class对象执行getRuntime
方法获得返回的实例化对象后再执行exec
方法
设置暴力访问权限
在利用反射机制时,有的时候会遇到私有private
成员变量或方法,这个时候我们通过之前的方法则会报错
添加私有private
构造方法:
private User() {
this.name = "private";
this.age = 0;
}
我们使用之前的反射获取该构造器并进行创建类对象实例
import java.lang.reflect.Constructor;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class<?> aClass = Class.forName("com.reflect.User");
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
User xiaozhu = (User) declaredConstructor.newInstance();
xiaozhu.Hello();
}
}
这个时候我们就要想办法绕过私有权限来访问,通过调用AccessibleObject
上的setAccessible
方法来允许访问。
import java.lang.reflect.Constructor;
public class ReflectClass {
public static void main(String[] args) throws Exception{
Class<?> aClass = Class.forName("com.reflect.User");
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
User xiaozhu = (User) declaredConstructor.newInstance();
xiaozhu.Hello();
}
}
这里的Java.lang.reflect.AccessibleObject
类是Field
,Method
和Constructor
类对象的基类,它提供了将反射对象标记为在使用它时抑制默认Java语言访问控制检查的功能。
所以对于私有private的成员变量或方法,都可以通过setAccessible
来恢复访问!
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectClass {
public static void main(String[] args) throws Exception{
// 获取私有private构造器创建实例化对象
Class<?> aClass = Class.forName("com.reflect.User");
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
User xiaozhu = (User) declaredConstructor.newInstance();
// 获取私有private成员变量age并修改
Field field = aClass.getDeclaredField("age");
field.setAccessible(true);
field.set(xiaozhu, 8);
// 获取私有private成员方法Hi(String name)并执行
Method declaredMethod = aClass.getDeclaredMethod("Hi", String.class);
declaredMethod.setAccessible(true);
declaredMethod.invoke(xiaozhu, "xiaozhu");
}
}
参考文章
Java安全|反射看这一篇就够了 - FreeBuf网络安全行业门户
标签:反射,Java,String,Class,class,reflect,User,机制,public From: https://www.cnblogs.com/seizer/p/17052833.html