huarui bio photo

java反射


写在前面


最近花了很长的时间去学习java,前后把Java se ,Java web,spring boot都搞了一遍(还搞了个springboot项目当练手): Bilibili-Film-Area-top-webcrawler。现在终于有心回来搞安全了


最近打算开始学链子的内容,从反射开始一步一步走。反正考完数电无事可做,就当是消磨时间了


举例


例子:

public class testForName {
    public static void main(String args[]) throws ClassNotFoundException, NoSuchMethodException {
        Class c = Class.forName("student");
        Class c1 = new student(2,"wm").getClass();
        Class c2 = student.class;
        //c,c1,c2指向同一个Class对象
        System.out.println(c2.getMethod("getName"));
 
        Class c3 = c.getSuperclass();
        System.out.println(c3.getMethod("getJob"));
    }
}
 
class person{
    private String job = "工人";
 
    public String getJob() {
        return job;
    }
 
    public void setJob(String job) {
        this.job = job;
    }
}
class student extends person{
    private int id = 0;
    private String name = "mak";
 
    public int getId() {
        return id;
    }
 
    public String getName() {
        return name;
    }
 
    public student(int id, String name) {
        this.id = id;
        this.name = name;
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    @Override
    public String toString() {
        return "student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}



获取Class对象:


1.通过类名

Class c = Class.forName("student");

Class.forName(“类名”) 即后文的student类


2.通过实例

Class c1 = new student(2,"wm").getClass();

这里是通过Object的getClass方法获得一个对象对应的类的Class对象。大概意思就是通过一个实例化之后的对象找到对应的class对象,有点绕


3.通过类名.class

Class c2 = student.class;

和第一种方法差不多,如果有新的理解我再补充


获取对象中的方法:


System.out.println(c2.getMethod("getName"))

通过getMethod方法获取 student 类中的 getName 方法。


获取父类的方法

Class c3 = c.getSuperclass();
System.out.println(c3.getMethod("getJob"));

c.getSuperclass()意思是获取 student 的父类 Class 对象,这里是 person 类。 通过getMethod方法在 person 类中获得 getJob 方法。


操作对象


接下来以这个类来举例

class student {
    private int id = 0;
    private String name = "mak";
 
    public int getId() {
        return id;
    }
 
    public String getName() {
        return name;
    }
 
    public student(int id, String name) {
        this.id = id;
        this.name = name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    void test(String name){
        System.out.println("hello,"+this.name+" and "+name);
    }
 
    @Override
    public String toString() {
        return "student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}


通过反射创造对象:


Class stuclass = Class.forName("student");
student stu = (student)stuclass.newInstance();

首先是获取 student 类的 Class 对象,这个在前面有讲,不在叙述。 student stu = (student)stuclass.newInstance(); 这句话的目的其实是创建一个student类的一个名叫stu实例。 stuclass.newInstance()会通过 student 类的无参构造函数来创建一个 student 类的对象。这里要求 student 类必须有一个无参构造函数。而newInstance() 返回一个 Object 类型,所以需要进行类型转换 (student),将返回的对象强制转换为 student 类型。


通过反射创造带参构造器的对象:


Constructor constr = stuclass.getConstructor(int.class,String.class); //获取类的构造器,参数:构造器参数类型的class
student stu1 = (student) constr.newInstance(12,"Tom");

stuclass.getConstructor(int.class, String.class) 用于获取 student 类中接受 int 和 String 两个参数的构造函数。

这里对应了例子中的:

    public student(int id, String name) {
        this.id = id;
        this.name = name;
    }

关于Constructor 对象:

Constructor 对象是 Java 反射机制中的一部分,用于表示类的构造函数。它的存在是为了提供一种方式,允许程序在运行时动态地访问和使用构造函数创建对象实例。与 Method 对象(用于表示普通方法)类似,Constructor 对象专门负责构造函数的管理。


执行对象方法


Method stname = stuclass.getMethod("setName", String.class); //获取类的方法,参数:方法名,方法参数类型的Class
stname.invoke(stu1,"wm"); //invoke(激活):执行函数,参数:(用于执行函数的对象,函数参数)
Method hello = stuclass.getDeclaredMethod("test", String.class);
hello.invoke(stu1,"abc");

stuclass.getMethod(“setName”, String.class):从 stuclass(即 student 类的 Class 对象)中获取 setName 方法。 getMethod() 的第一个参数是方法名,第二个参数是方法的参数类型

stname.invoke(stu1, “wm”):通过反射调用 stname 方法,即调用 stu1 对象的 setName 方法,并传入参数 “wm”。

hello方法同理,不在叙述

操作对象属性


Field stuid = stuclass.getDeclaredField("name");
stuid.setAccessible(true); //对于修改private属性,要先关闭程序安全检测(默认为true)
stuid.set(stu1,"wm1111"); //set修改,参数:要修改属性的对象,修改后的值
hello.invoke(stu1,"def");

通过反射来访问并修改 student 类的私有属性 name,然后再次调用 test 方法

stuclass.getDeclaredField(“name”):从 stuclass(即 student 类的 Class 对象)中获取 name 字段(即属性)

关于set方法:

set() 方法不是 Class 类,而是 Field 类 的方法。Field 类在 java.lang.reflect 包中,用于表示类的属性(字段)。通过 Field 对象的 set() 方法,可以为特定对象的字段设置值。


写在后面


唉,体测