反射概念
Java反射机制是在运行状态时,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制。
简单讲让其具有动态特性。
动态特性即⼀段代码,改变其中的变量,将会导致 这段代码产⽣功能性的变化,我称之为动态特性。
JAVA 常用的方法
获取类的⽅法: forName
实例化类对象的⽅法: newInstance
获取函数的⽅法: getMethod
执⾏函数的⽅法: invoke
public void execute(String className, String methodName) throws Exception {
Class clazz = Class.forName(className);
clazz.getMethod(methodName).invoke(clazz.newInstance());
}
Java 反射组成相关的类
反射机制相关操作一般位于java.lang.reflect包中。
而java反射机制组成需要重点注意以下的类:
java.lang.Class:类对象;
java.lang.reflect.Constructor:类的构造器对象;
java.lang.reflect.Field:类的属性对象;
java.lang.reflect.Method:类的方法对象;
反射的简单使用
1.实例化对象
JVM为每个加载的class创建了对应的Class实例,并在实例中保存了该class的所有信息;因此,如果获取了某个Class实例,我们就可以通过这个Class实例获取到该实例对应的class的所有信息
0x01 直接通过一个class的静态变量class获取:
Class c = String.class;
0x02 通过该实例变量提供的getClass()方法获取:
String s = "test";
Class c = s.getClass();
0x03 知道一个class的完整类名,可以通过静态方法Class.forName()获取
Class c = Class.forName("java.lang.String");
由于Class实例在JVM中是唯一的,所以,上述方法获取的Class实例是同一个实例.
2.获取成员变量 Field
获取成员变量Field位于 java.lang.reflect.Field 包中
Field[] getFields() :获取所有 public 修饰的成员变量,包括父类中的变量。
Field[] getDeclaredFields() 获取所有的成员变量,即包括public、private和proteced,但是不包括父类的申明变量。
Field getField(String name) 获取指定名称的 public 修饰的成员变量
Field getDeclaredField(String name) 获取指定的成员变量
package ysoserial.mytest;
import java.lang.reflect.Field;
public class test {
public static void main(String[] args) throws Exception {
Class stiClass = StuInfo.class;
// 获取public字段"age":
System.out.println(stiClass.getField("age"));
// 获取继承的public字段"name":
System.out.println(stiClass.getField("name"));
// 获取private字段"money":
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,2);
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 = "test";
}
3. 获取成员方法 Method
Class类提供了以下几个方法来获取Method:
- Method getMethod(name, Class...):获取某个public的Method(包括父类)
- Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)
- Method[] getMethods():获取所有public的Method(包括父类)
- Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)
通过反射来使用substring
String name = "test123";
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);
4.获取构造函数 Constructor
通过Class实例获取Constructor的方法如下:
getConstructor(Class...):获取某个public的Constructor;
getDeclaredConstructor(Class...):获取某个Constructor;
getConstructors():获取所有public的Constructor;
getDeclaredConstructors():获取所有Constructor。
调用非public的Constructor时,必须首先通过setAccessible(true)设置允许访问。setAccessible(true)可能会失败。
反射的进阶使用
反射创建对象
Class c = Class.forName("类的名称"); // 创建Class对象
Object m1 = c.newInstance(); // 创建类对象
反射修改被final关键字修饰的成员变量
// 反射获取Field类的modifiers
Field modifiers = field.getClass().getDeclaredField("modifiers");
// 设置modifiers修改权限
modifiers.setAccessible(true);
// 修改成员变量的Field对象的modifiers值
modifiers.setInt(field, field.getModifiers() &~Modifier.FINAL);
// 修改成员变量值
field.set(类实例对象, 修改后的值);
利用反射弹计算器
package org.example;
import java.lang.reflect.Method;
public class ReflectionTest01 {
public static void main(String[] args) throws Exception{
Class c1 = Class.forName("java.lang.Runtime");
Method method = c1.getMethod("exec", String.class);
Method RuntimeMethod = c1.getMethod("getRuntime");
Object o1 = RuntimeMethod.invoke(c1);
method.invoke(o1, "deepin-calculator");
}
}
写到一句话
package org.example;
import java.lang.reflect.Method;
public class ReflectionTest01 {
public static void main(String[] args) throws Exception{
/*Class c1 = Class.forName("java.lang.Runtime");
Method method = c1.getMethod("exec", String.class);
Method RuntimeMethod = c1.getMethod("getRuntime");
Object o1 = RuntimeMethod.invoke(c1);
method.invoke(o1, "deepin-calculator");*/
//执行命令
Class.forName("java.lang.Runtime").getMethod("exec", String.class).invoke(Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime")),"deepin-calculator");
}
}