ycycyc

JAVA反射

2025-07-23

理解

有反射就必然有正射。

正射

编写代码的额时候,当我们需要使用一个类的时候,先要了解这个类是做什么的。然后实例化这个类,接着用实例化好的对象进行操作,这就是正射。如下:

Student student = new Student();
student.doHomework("数学");

反射

反射就是一开始不知道我们要初始化的类的对象是什么,也就无法使用new关键字来创建对象了。

 Class clazz = Class.forName("reflection.Student");
Method method = clazz.getMethod("doHomework", String.class);
Constructor constructor = clazz.getConstructor();
Object object = constructor.newInstance();
method.invoke(object, "语文");

通过类的全限定名获取对象,然后获取对象中的doHomework的方法,接受一个String类型的参数,然后获取对象的无参构造函数,调用无参构造函数创建类的实例,即调用无参构造函数创建 reflection.Student 类的一个对象,最后调用object对象的doHomework方法,传入语文作为参数。

这里与正射的根本区别就是这里的类名reflection.Student是动态获取的,可以是输入的内容,也可以是从其他地方获得的内容。

这两段正射和反射的代码的执行效果相同,但是实现的过程有很大的区别:

正射的代码是在未运行前就知道要执行的类是Student类

反射的代码是在整个程序运行的时候,从字符串reflection.Student才知道的要操作的类是Student

JAVA Class对象的理解

下面是ReflectionTest.java的内容

package fanxu;

public class ReflectionTest {
    public static void main(String[] args) throws Exception{
        Person person = new Person();
        Class c = person.getClass();
    }
}

首先要搞清楚这里的Class是什么:

程序在运行的时候会编译生成一个 .class 文件(JAVA的字节码文件),而这个 .class 文件中的内容就是相对应的类的所有信息

这里的person.class(person类编译后生成的.calss文件)其实就是Class,所以Class就是描述类的类

Class 类的对象作用是运行时提供或获得某个对象的类型信息

所以反射其实就是操作Class

JAVA反射组成的相关的类

反射的相关的操作一般发生在java.lang.reflect包中

java反射机制组成需要注意的类:

java.lang.Class:类对象

java.lang.reflect.Constructor:类的构造器对象

java.lang.reflect.Field:类的属性对象;

java.lang.reflect.Method:类的方法对象;

JAVA反射的使用方法

下面关于java反射如何利用和实现,以及如何辅助进行反弹shell进行介绍。

获取类的方法:forName

实例化类对象的方法:newInstance

获取函数的方法:getMethod

执行函数的方法:invoke

1.实例化对象

普通用户的实例化

Person a=new Person();

创建Class类的实例化对象的时候不能够使用同样的方法会报错。

跟进Class类的源码查看实现了源码的跟踪

image-20250718204519547

发现Class类的构造器是私有属性的,所以无法通过创建对象的方式获取Class对象

获取class对象的方法有以下的三种:

方法一:实例化对象的getClass()方法

上下文存在某个类的实例obj,可以通过obj.getClass来获取他的类

示例

TestReflection testReflection = new TestReflection();
Class class3 = testReflection.getClass();

方法二:使用类的.class方法

Class class2 = TestReflection.class;

方法三:使用Class.forName()静态方法

前具体是知道这个类的名字

Class class1 = Class.forName("reflection.TestReflection");

测试

package fanxu;

public class ReflectionTest {
    public static void main(String[] args) throws Exception{
        // 类的 .class 属性
        Class c1 = Person.class;
        System.out.println(c1.getName());

        // 实例化对象的 getClass() 方法
        Person person = new Person();
        Class c2 = person.getClass();
        System.out.println(c2.getName());

        // Class.forName(String className): 动态加载类
        Class c3 = Class.forName("fanxu.Person");
        System.out.println(c3.getName());

    }
}

image-20250719203636628

2.获取成员变量

获取成员变量Field位于 java.lang.reflect.Field 包中

Field[] getFields() :获取所有 public 修饰的成员变量

Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符

Field getField(String name) 获取指定名称的 public 修饰的成员变量

Field getDeclaredField(String name) 获取指定的成员变量

3.获取成员方法Method

第一个参数是传参,第二个参数是确定重载的是哪个函数。

Method getMethod(String name, 类<?>... parameterTypes) //返回该类所声明的public方法

Method getDeclaredMethod(String name, 类<?>... parameterTypes) //返回该类所声明的所有方法


//第一个参数获取该方法的名字,第二个参数获取标识该方法的参数类型,参数类型后面加上.class


Method[] getMethods() //获取所有的public方法,包括类自身声明的public方法,父类中的public方法、实现的接口方法

Method[] getDeclaredMethods() // 获取该类中的所有方法

测试

person.java

package fanxu;

public class person {
    public void study(String s) {
        System.out.println("学习中..." + s);
    }
    private String sleep(int age) {
        System.out.println("睡眠中..." + age);
        return "sleep";
    }
}

ReflectionTest.java

package fanxu;


import java.lang.reflect.Method;

public class ReflectionTest {
    public static void main(String[] args) throws Exception{
        Class c1 = Class.forName("fanxu.person");// 创建 Class 对象
        Method[] methods1 = c1.getDeclaredMethods();// 获取所有该类中的所有方法
        Method[] methods2 = c1.getMethods();// 获取所有的 public 方法,包括类自身声明的 public 方法,父类中的  、实现的接口方法

        for (Method m:methods1){
            System.out.println(m);
        }
        System.out.println("-------分割线---------");

        for (Method m:methods2) {
            System.out.println(m);
        }

        System.out.println("-------分割线---------");

        Method methods3 = c1.getMethod("study", String.class);// 获取 Public 的 study 方法
        System.out.println(methods3);
        System.out.println("-------分割线---------");

        Method methods4 = c1.getDeclaredMethod("sleep", int.class); // 获取 Private 的 sleep 方法
        System.out.println(methods4);
    }

}

运行结果如下

4.获取构造函数Constructor

Constructor<?>[] getConstructors() :只返回public构造函数

Constructor<?>[] getDeclaredConstructors() :返回所有构造函数

Constructor<> getConstructor(<?>... parameterTypes) : 匹配和参数配型相符的public构造函数

Constructor<> getDeclaredConstructor(<?>... parameterTypes) : 匹配和参数配型相符的构造函数

在 forName 之后获取构造函数

新建PersonConstructor.java

package fanxu;

import java.io.Serializable;

public class PersonConstructor {

    private String name;
 private int age;

 // 无参构造
 public PersonConstructor(){

    }
    // 构造函数
 public PersonConstructor(String name, int age){
        this.name = name;
 this.age = age;
 }
    // 私有构造函数
 private PersonConstructor(String name){
        this.name = name;
 }

    @Override
 public String toString(){
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
 }

}

ReflectionTest03.java

package fanxu;

import java.lang.reflect.Constructor;

public class ReflectionTest03 {
    public static void main(String[] args) throws Exception{
        Class c1 = Class.forName("fanxu.PersonConstructor");
 Constructor[] constructors1 = c1.getDeclaredConstructors();
 Constructor[] constructors2 = c1.getConstructors();
 for (Constructor c : constructors1){
            System.out.println(c);
 }
        System.out.println("-------分割线---------");
 for (Constructor c : constructors2){
            System.out.println(c);
 }
        System.out.println("-------分割线---------");
 Constructor constructors3 = c1.getConstructor(String.class, int.class);
 System.out.println(constructors3);
 System.out.println("-------分割线---------");
 Constructor constructors4 = c1.getDeclaredConstructor(String.class);
 }
}

运行结果如下

image-20250719214842658

反射的作用

让JAVA具有动态性

反射常用的方面

修改已有的对象的属性

动态生成对象

动态调用方法

操作内部类和私有的方法

反射进阶

反射创建对象

反射创建对象,也叫做反射之后实例化对象,这里用到的是我们之前讲过的 newInstance() 方法

Class c = Class.forName("类的名称"); // 创建Class对象
Object m1 =  c.newInstance(); // 创建类对象

invoke 方法,invoke 方法位于 java.lang.reflect.Method 类中,用于执行某个的对象的目标方法。
一般会和 getMethod 方法配合进行调用。

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

第一个参数为类的实例,第二个参数为相应函数中的参数

obj:从中调用底层方法的对象,必须是实例化对象

但需要注意的是,invoke 方法第一个参数并不是固定的:

如果调用这个方法是普通方法,第一个参数就是类对象;

如果调用这个方法是静态方法,第一个参数就是类;

测试

首先在person类添加上reflect()方法

ReflectionTest04

package fanxu;

import java.lang.reflect.Method;

public class ReflectionTest04 {
    public static void main(String[] args) throws Exception{
        Class c1 = Class.forName("fanxu.person");  //通过全限定名获取Class对象
 Object m = c1.newInstance();  //创建类的对象
 Method method = c1.getMethod("reflect");  //获取reflect无参方法
 method.invoke(m);  //在对象m上面调用获取到的方法
 }
}

执行结果

image-20250721145516984

← Back to Home