当然不可能什么都记录,只记录一些对我有用的
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
(不包括父类)
简单来通过反射来使用substring
String 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");
// 反射获取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();
}
}
}