写在前面

第一次学习java反射,可能有些错误,希望师傅们能及时指正我QAQ

什么是反射

  1. 反射机制的核心是在程序运行时动态加载类并获取类的各种信息,从而操作类或者对象的属性方法
    本质是:JVM得到class对象后,再通过class对象进行反编译,从而获得对象的各种信息
  2. Java属于先编译再运行的语言,程序中对象的类型再编译器就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所有没有被加载到JVM中,通过反射,就可以再运行时动态的创建对象并调用其属性和方法,不需要提前在编译期知道运行的对象是谁

反射常用的类

  • Java.lang.Class
  • Java.lang.reflect.Field
  • Java.lang.reflect.Method
  • Java.lang.reflect.Constructor
  • Java.lang.reflect.Modifier

先抛出我写的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Member{
public String name;
protected int age;
private String sex;

public Member() {
System.out.println("这是无参构造函数");
}

public void aaa(int num){
System.out.println("今年是"+num+"年");
}

private void bbb(int num){
System.out.println("本月是"+num+"月");
}
@Override
public String toString() {
return "Member{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}

Class类对象的获取

  1. 根据类名:类名.class
  2. 根据对象:对象.getClass()
  3. 根据路径包:Class.forName(“绝对路径”)
1
2
3
4
5
6
7
8
9
10
//1.通过.class
Class memberClass = Member.class;

//2.通过getClass
Member member = new Member();
Class aClass = member.getClass();//前提是要有对象名member,才能getClass

//3.通过类的路径
Class aClass1 = Class.forName("com.Reflection.Member");//需要知道路径

通过观察hashcode发现三者相等

获取Class类对象的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//        //1.通过.class
// Class aClass = Member.class;
//
// //2.通过getClass
// Member member = new Member();
// Class aClass = member.getClass();//前提是要有对象名member,才能getClass
//
// //3.通过类的路径
Class aClass = Class.forName("com.Reflection.Member");//需要知道路径
//以上三者方法任选之一
//获取字段变量
Field name = aClass.getField("name");
Field age = aClass.getField("age");
Field sex = aClass.getField("sex");

我们发现这里报错了,说代码36行age出现了问题
回首我们发现,age是属于protected的类型,sex是属于private
getFileld只能获得public的属性,那么怎样才能获得protected和private呢?
getDeclaredField是专门用来获取所有得属性或者方法(包括了protected和private)

换掉之后便不在报错了~
记得要加 对象.setAccessible(true) ,用来解除private和protect

获取Class类对象的方法

1
2
Method aaa = aClass.getMethod("aaa", int.class);
Method bbb = aClass.getDeclaredMethod("bbb", int.class);

也是一样的,用getDeclaredMethod获得private和protect

class.newInstance()

会调用这个类得无参构造函数
有时候我们会newInstance不成功,原因如下:

  1. 你使用得类没有无参构造函数
  2. 你使用得类构造函数是私有的
1
2
Object obj = aClass.newInstance();
System.out.println(obj);

尝试输出一下


提问:

  1. 如果一个类没有无参构造方法,也没有静态模块,那么我们应该怎样通过反射实例化这个类呢?
  2. 如果一个方法或者构造方法是私有方法,我们是否能执行它了?

解答

解答一:

我们这时候就要用到一个新的反射方法getConstructor
它与getMethod的用法相似,获得构造函数后,使用newInstance来执行

1
2
3
4
Method declaredMethod = aClass.getDeclaredMethod("aaa", int.class);
Constructor declaredConstructor = aClass.getDeclaredConstructor();
Object o = declaredConstructor.newInstance();
declaredMethod.invoke(o,2022);

解答二:

答案很简单,就是直接用getDeclared
记得要加 对象.setAccessible(true) ,用来解除private和protect

整个源代码给出

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package com.Reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test11 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {

// //1.通过.class
// Class memberClass = Member.class;
//
// //2.通过getClass
// Member member = new Member();
// Class aClass = member.getClass();//前提是要有对象名member,才能getClass
//
// //3.通过类的路径
// Class aClass1 = Class.forName("com.Reflection.Member");//需要知道路径
//
// //我们可以判断这三个是否相等
// System.out.println(memberClass.hashCode());
// System.out.println(aClass.hashCode());
// System.out.println(aClass1.hashCode());

// //1.通过.class
// Class aClass = Member.class;
//
// //2.通过getClass
// Member member = new Member();
// Class aClass = member.getClass();//前提是要有对象名member,才能getClass
//
// //3.通过类的路径
Class aClass = Class.forName("com.Reflection.Member");//需要知道路径
//以上三者方法任选之一

Field name = aClass.getField("name");
Field age = aClass.getDeclaredField("age");
Field sex = aClass.getDeclaredField("sex");

Method bbb = aClass.getDeclaredMethod("bbb", int.class);
Method aaa = aClass.getDeclaredMethod("aaa", int.class);

Constructor declaredConstructor = aClass.getDeclaredConstructor();
Object o = declaredConstructor.newInstance();//实例化,然后执行无参构造语句


name.set(o,"CQJKL");
age.setAccessible(true);//解除私有
age.set(o,10);
sex.setAccessible(true);//解除私有
sex.set(o,"boy");
System.out.println(o);

aaa.invoke(o,2022);
bbb.setAccessible(true);//解除私有
bbb.invoke(o,5);

}

}

class Member{
public String name;
protected int age;
private String sex;

public Member() {
System.out.println("这是无参构造函数");
}

public void aaa(int num){
System.out.println("今年是"+num+"年");
}

private void bbb(int num){
System.out.println("本月是"+num+"月");
}
@Override
public String toString() {
return "Member{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}

再更新


这两天中秋节,花了两个早上把韩顺平老师的java反射给刷了一遍
这里来贴上韩老师的相关代码,经过自己改编的QAQ
师傅们可以看看我写的有没有问题,哈哈

构造器实例

  1. 方式一:调用类中二点public修饰的无参构造器
  2. 方式二:调用类中的指定构造器
  3. Class类相关方法
  • newInstance:调用类中的无参构造器,获取对应类得对象
  • getConstructor:根据参数列表,获取对于得构造器对象
  • getDecalaredConstructor:根据参数列表,获取对应得构造器对象
  1. Constructor类相关方法
  • setAccessible:爆破
  • newInstance:调用构造器
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
55
56
package com.Reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class demo1 {

public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
//1.先获取Persion类
Class<?> cls = Class.forName("com.Reflection.Persion");

//2.获取public的无参构造
Object o = cls.newInstance();
System.out.println(o);
System.out.println("======================================");
//3.通过public的有参构造
Constructor<?> constructor = cls.getConstructor(String.class);
Object cqjkl = constructor.newInstance("cqjkl");
System.out.println(cqjkl);
System.out.println("======================================");
//4.通过非public的有参构造器
Constructor<?> declaredConstructor = cls.getDeclaredConstructor(int.class, String.class);
declaredConstructor.setAccessible(true);
Object CQjkl = declaredConstructor.newInstance(55, "CQjkl");
System.out.println(CQjkl);


}
}


class Persion{
private int age = 10;
private String name = "CQJKL";

public Persion() {
}
public Persion(String name)
{
this.name = name;
}

private Persion(int age, String name){
this.age = age;
this.name = name;
}

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

属性实例

  1. 根据属性名获取Field对象
  • Field f = clazz对象.getDeclaredField(属性名);
  1. 爆破:f.setAccessible(true);
  2. 访问
  • f.set(o,value)
  • System.out.println(f.get(o));
  1. 如果是静态属性,则set和get中得参数o,可以写成null
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
package com.Reflection;

import java.lang.reflect.Field;

public class demo2 {

public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
//1.得到Stu类
Class<?> stu = Class.forName("com.Reflection.Stu");
//2.创建对象
Object o = stu.newInstance();
System.out.println(o);
//3.获得属性
Field age = stu.getField("age");
age.set(o,55);
System.out.println(age.get(o));
Field name = stu.getDeclaredField("name");//name为private
name.setAccessible(true);//爆破private
name.set(o,"cqjkl");
System.out.println(name.get(o));
System.out.println(o);


}
}

class Stu{
public int age = 5;
private String name = "CQJKL";

public Stu(){

}

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

方法实例

  1. 根据方法名和参数列表获取Method方法对象:Method m = clazz.getDeclaredMethod(方法名,XX.class);
  2. 获取对象:Object o = clazz.newInstance();
  3. 爆破:m.setAccessible(true);
  4. 访问:Object returnValue = m.invoke;
  5. 注意:如果是静态方法,则invoke的参数o,可以写成null
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
package com.Reflection;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class demo3 {

public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {

//1.获取Boss类
Class<?> boss = Class.forName("com.Reflection.Boss");
//2.创建对象
Object o = boss.newInstance();
//3.得到public的hi方法
Method hi = boss.getMethod("hi", String.class);
//4.调用hi
hi.invoke(o, "CQJKL");

//5.调用say,private,爆破
Method say = boss.getDeclaredMethod("say", int.class, String.class, char.class);
say.setAccessible(true);
System.out.println(say.invoke(o,55,"jk",'H'));
Object invoke = say.invoke(null, 44, "JK", 'M');
System.out.println(invoke);


}
}

class Boss{
public int age;
private static String name;

public Boss(){

}
private static String say(int n, String s, char c){
return n + " " + s + " " + c;
}

public void hi(String s){
System.out.println("hi "+ s);
}
}

参考

https://www.cnblogs.com/chanshuyi/p/head_first_of_reflection.html

https://blog.csdn.net/a745233700/article/details/82893076

https://www.bilibili.com/video/BV1g84y1F7df?p=1&vd_source=69176eb1fdd50fb68253b31fc93080b0

https://www.bilibili.com/video/BV1p4411P7V3?spm_id_from=333.999.0.0&vd_source=69176eb1fdd50fb68253b31fc93080b0

<P牛-代码审计-Java安全漫谈-反射篇-3篇>