Refelction

反射

Java反射机制是在运行状态时,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制。

获取类

JVM为每个加载的class创建了对应的Class实例,并在实例中保存了该class的所有信息;因此,如果获取了某个Class实例,我们就可以通过这个Class实例获取到该实例对应的class的所有信息。

常用的由以下几种方式获取类:

1
2
3
4
5
6
7
8
9
10
11
12
// 1.由静态属性class获取
Class clazz = String.class;

// 2.由getClass()获取
String s = "";
Class clazz = s.getClass();

// 3.Class.forName()
Class clazz = Class.forName("java.lang.String");

//4.ClassLoader
Class<?> clazz = this.getClass().getClassLoader().loadClass("com.spring.sec.ClassLoader.reflectTest");

获取类之后就可以对类进行访问修改等操作,值得注意的是,上述四种方法所获取的Class实例是同一个。

获取属性

1
2
3
4
5
6
7
8
9
10
11
Class<?> clazz = Class.forName("com.spring.sec.reflectTest");

Field[] fields = clazz.getFields();
//获得类(包括父类)中所有的public属性。
Field field = clazz.getField("property");
//获得类(包括父类)中指定的public属性。

Field[] declaredFields = clazz.getDeclaredFields();
//获得某个类的所有声明的属性,包括public、private和proteced,但不包括父类的申明属性。
Field declaredField = clazz.getDeclaredField("property");
//获得某个类中的指定属性,包括public、private和proteced,但不包括父类的申明属性。

对于获取到的属性,我们想要在具体的实例中获取需要使用get()方法,修改需要使用set()方法.

1
2
3
4
Object o = field.get(clazz.newInstance());
//获取实例中的属性
field.set(clazz.newInstance(),"edited_property");
//修改实例中的属性

另外对于privateprotected修饰的属性需要先设置可编辑才能修改:

1
privateField.setAccessible(true);//设置可修改

获取方法

getMehtod() 其原型是

1
2
public reflect.Method getMethod(@NonNls @NotNull String name,
Class<?>... parameterTypes)

一些例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Class<?> clazz = Class.forName("com.spring.sec.reflectTest");

Method[] methods = clazz.getMethods();
//获取所有public的Method(包括父类)
Method method = clazz.getMethod("name");
//获取某个public的Method(包括父类)

Method[] methods = clazz.getDeclaredMethods();
//获取类中所有的Methods(不包括父类)
Method method = clazz.getDeclaredMethod("name");
//获取类中的某个Method(不包括父类)

//若要指定方法重载,可以添加参数parameterTypes
Method method = clazz.getDeclaredMethod("name",String.class);
//获取参数列表为<String>的方法,识别重载

调用: invoke()

获取方法后执行需要调用invoke(),其原型是

1
public Object invoke(Object obj, Object... args)

obj是实例,args是参数例如

1
2
3
4
method.invoke(clazz,new String("springtime"));

//无参方法第二个参数为空
method.invoke(clazz);

注意:若调用的方法为静态方法,则第一个参数必须是null

1
2
3
4
5
// 获取Integer.parseInt(String)方法,参数为String:
Method m = Integer.class.getMethod("parseInt", String.class);
// 调用该静态方法并获取结果:
Integer n = (Integer) m.invoke(null, "23333");
System.out.println(n);

获取构造器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Constructor<?> constructor = clazz.getConstructor();
//获取某个public的无参Constructor
Constructor<?> constructor = clazz.getDeclaredConstructor()
//获取某个无参Constructor

Constructor<?> constructor = clazz.getConstructor(...parameterTypes)
//获取某个public的指定参数的constructor
Constructor<?> constructor = clazz.getDeclaredConstructor(...parameterTypes)
//获取某个指定参数的constructor

Constructor<?>[] constructors = clazz.getConstructors();
//获取所有public的Constructor
Constructor<?>[] Constructors = clazz.getDeclaredConstructors();
//获取所有Constructor

实例化: newInstance()

注意:java.lang.Class.newInstance()java.lang.refelct.Constructor.newInstance()不同,前者是无参构造方法调用,而后者是构造方法重载调用。

1
2
Object o = clazz.newInstance();//无参
Object o = constructor.newInstance(@Nullable Object... initargs);

修改final关键字修饰的属性

被final关键字修饰的属性我们无法使用set()方法修改,需要借助类中的modifiers

1
2
3
4
5
6
7
8
9
10
11
// 反射获取Field类的modifiers
Field modifiers = field.getClass().getDeclaredField("modifiers");

// 设置modifiers修改权限
modifiers.setAccessible(true);

// 修改成员变量的Field对象的modifiers值
modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);

// 修改成员变量值
field.set(obj, "edited_value");

反射命令执行

1
Class.forName("java.lang.Runtime").getMethod("exec",String.class).invoke(Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime")),"calc.exe");

高版本JDK下的反射

@TODO


Refelction
http://example.com/2022/12/28/Refelction/
Author
springtime
Posted on
December 28, 2022
Licensed under