反射概念

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");
    }
}

JAVA执行命令的三种方式

0x01 调用 Runtime 类进行命令执行

0x02 ProcessBuilder

0x03 使用 ProcessImpl