Java反射
- Java安全
- 2023-08-31
- 3261热度
- 4评论
反射
概念
Java反射机制是在运行状态时,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制。
Java如何获取一个类
JVM为每个加载的class创建了对应的Class实例,并在实例中保存了该class的所有信息;因此,如果获取了某个Class实例,我们就可以通过这个Class实例获取到该实例对应的class的所有信息
1.直接通过一个class的静态变量class获取:Class cls = String.class;
2.通过该实例变量提供的getClass()方法获取String s = "Y4";
Class cls = s.getClass();
3.知道一个class的完整类名,可以通过静态方法Class.forName()获取Class cls = Class.forName("java.lang.String");
并且说明一点,由于Class实例在JVM中是唯一的,所以,上述方法获取的Class实例是同一个实例
访问字段
getFields():获得某个类的所有的公共(public)的字段,包括父类中的字段。 getDeclaredFields():获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的申明字段。package ysoserial.mytest;
import java.lang.reflect.Field;
public class test {
public static void main(String[] args) throws Exception {
Class stiClass = StuInfo.class;
// 获取public字段"score":
System.out.println(stiClass.getField("age"));
// 获取继承的public字段"name":
System.out.println(stiClass.getField("name"));
// 获取private字段"grade":
System.out.println(stiClass.getDeclaredField("money"));
// 获得值,name.get里面参数需要该类对象,而不是.class
Field name = stiClass.getField("name");
System.out.println(name.get(stiClass.newInstance()));
// 设置值
StuInfo stuInfo = new StuInfo();
Field money = stiClass.getDeclaredField("money");
money.setAccessible(true);
money.set(stuInfo,2333333);
System.out.println(stuInfo);
}
}
class StuInfo extends PersonInfo{
public int age;
private int money;
@Override
public String toString() {
return "StuInfo{" +
"name=" + name +
", money=" + money +
'}';
}
}
class PersonInfo{
public String name = "Y4tacker";
}
获取方法
Class类提供了以下几个方法来获取Method:
Method getMethod(name, Class...):获取某个public的Method(包括父类)Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)Method[] getMethods():获取所有public的Method(包括父类)Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)
简单来通过反射来使用substringString name = "Y4tacker";
Method substring = String.class.getMethod("substring", int.class);
System.out.println(substring.invoke(name,3));
如果调用的方法是静态方法。那么invoke方法传入的第一个参数永远为null// 获取Integer.parseInt(String)方法,参数为String:
Method m = Integer.class.getMethod("parseInt", String.class);
// 调用该静态方法并获取结果:
Integer n = (Integer) m.invoke(null, "23333");
System.out.println(n);
获取构造方法
通过Class实例获取Constructor的方法如下:
getConstructor(Class...):获取某个public的Constructor;getDeclaredConstructor(Class...):获取某个Constructor;getConstructors():获取所有public的Constructor;getDeclaredConstructors():获取所有Constructor。
调用非public的Constructor时,必须首先通过setAccessible(true)设置允许访问。setAccessible(true)可能会失败。
反射执行命令
Class.forName("java.lang.Runtime").getMethod("exec", String.class).invoke(Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime")),"calc");
反射修改被final关键字修饰的成员变量
// 反射获取Field类的modifiers
Field modifiers = field.getClass().getDeclaredField("modifiers");
// 设置modifiers修改权限
modifiers.setAccessible(true);
// 修改成员变量的Field对象的modifiers值
modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
// 修改成员变量值
field.set(类实例对象, 修改后的值);
因此我们这里给一个具体实例Class aClass = Class.forName("bcell.Test");
Test Test = (Test) aClass.newInstance();
Field field = aClass.getDeclaredField("TEST");
Field modifiers = field.getClass().getDeclaredField("modifiers");
modifiers.setAccessible(true);
modifiers.setInt(field,field.getModifiers()&~Modifier.FINAL);//fianl标志位置0
field.set(Test,"wocao");
System.out.println(field.get(Test));
其他
但是虽然这么多,其中较为重要的⽅法:
获取类的⽅法: forName
实例化类对象的⽅法: newInstance
获取函数的⽅法: getMethod
执⾏函数的⽅法: invoke
其中比较好玩的是第一种方式Class.forName(className)
// 等于
Class.forName(className, true, currentLoader
第⼆个参数表示是否初始化,在 forName 的时候,构造函数并不会执⾏,而是执⾏类初始化。他会执行static{}静态块里面的内容public class test {
public static void main(String[] args) throws Exception {
Class.forName("mytest.Calc");
}
}
class Calc{
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
e.printStackTrace();
}
}
}

:dinosaur-shy:
:dinosaur-crazy:
:dinosaur-sweat:
123