java反射技术学习

一、什么是反射

反射是指在程序运行时动态地获取类的信息,包括类名、字段、方法等。Java提供了一系列反射方法来操作(如获取、创建、修改、调用)Class对象、构造函数、方法、字段等。通过反射,我们可以创建对象、调用方法和访问字段,而不需要提前知道类的具体定义。同时反射也是一种实现动态加载的技术之一。

二、基于反射进行动态加载

贴一段用于辅助测试的代码:

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
package com.example.uu;
import com.test.wtf.Dog;

public class Test {

public String publicStr;
private String privateStr = "abc";

Dog dog;//另一个类,具体代码就不贴了

public Test(String publicStr) {
this.publicStr = publicStr;
this.dog = new Dog("ww");
}

public Test(){

}

public String getPublicStr() {
return publicStr;
}

public String getPublicStr(int a) {
return publicStr;
}

}

基于上面这段代码, 来学习如何使用Java反射。

2.1 类反射

2.1.1 获取类

  • Class.forName(ClassName):动态加载类,ClassName指定要加载的类名。
  • ClassLoader的loaderclass():动态加载类,ClassName指定要加载的类名。
  • 类名.class:非动态加载。
  • 类对象.getClass():非动态加载。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//1.Class.forName()
Class cl = Class.forName("com.example.uu.Test");
//2.ClassLoader
Class cl = ClassLoader.getSystemClassLoader().loadClass("com.example.uu.Test");
/*
输出:
class com.example.uu.Test
*/

//3.类名.class
Class sClass = String.class;
System.out.println(sClass);
/*
输出:
class java.lang.String
*/

//4.类对象.getClass()
String a = "a";
Class aClass = a.getClass();
System.out.println(aClass);

2.1.2 通过类获取类实例

  • class.newInstrance():执行无参构造获取类实例,该方法要求class类有无参构造方法。

示例代码

1
2
3
4
//1.获取类
Class cl = Class.forName("com.example.uu.Test");
//执行类的无参构造方法来获取类实例(必须要求该类含有无参构造方法)
Object o = cl.newInstance();

2.2 构造方法反射

2.2.1 获取构造方法

  • class.getConstructor(...ParameterTypes):获取class类中的public权限的构造方法,ParameterTypes指定所获取的构造方法中的参数的类型,没有则表示无参。
  • class.getConstructors():获取class类中的所有public权限的构造方法。
  • class.getDeclaredConstructor(...ParameterTypes) :获取class类中的任意构造方法。
  • class.getDeclaredConstructors():获取class类中的所有构造方法。

示例代码:

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
//1. 获取无参构造方法
Constructor constructor = cl.getConstructor();
System.out.println(constructor);
/*
输出:
public com.example.uu.Test()
*/

//2. 获取带一个参数且为string类型的构造方法
Constructor constructor = cl.getConstructor(String.class);
System.out.println(constructor);
/*
输出:
public com.example.uu.Test(java.lang.String)
*/

//3. 获取该类的所有构造方法
Constructor[] constructors = cl.getConstructors();
for (Constructor con:constructors) {
System.out.println(con);
System.out.println(con.getName() + "||" + con.getModifiers() + "||"
+ Arrays.toString(con.getParameters()) + "||"
+ Arrays.toString(con.getParameterTypes()));
}
/*
输出
public com.example.uu.Test(java.lang.String)
com.example.uu.Test||1||[java.lang.String arg0]||[class java.lang.String]
public com.example.uu.Test()
com.example.uu.Test||1||[]||[]
*/

2.2.2 通过构造方法获取类实例

  • constructor.newInstance(...args):通过constructor构造方法构造类实例对象,根据获取到的constructor构造方法来决定是否需要传入参数args
  • constructor.setAccessible(bool):设置constructor构造函数的访问权限,若bool为true则表示取消构造函数的访问权限控制,这意味着private声明的构造函数也可以进行访问。

示例代码:

1
2
3
4
5
6
7
8
9
//1.无参构造
Class cl = Class.forName("com.example.uu.Test");//获取类
Constructor constructor = cl.getConstructor();//通过类获取无参构造方法
Object o = constructor.newInstance();//执行构造方法获得类实例

//2.有参构造
Class cl= Class.forName("com.example.uu.Test");//获取类
Constructor constructor = cl.getConstructor(String.class);///获取带一个参数且参数类型为String类型的构造方法
Object obj = constructor.newInstance("aaaaaaaaaaaaaaaa");//执行构造方法获得类实例

2.3 字段反射

2.3.1 获取字段

  • class.getField(FieldName) :获取class类中的带public声明的FieldName变量。

  • class.getFields():获取class类中的带public声明变量。

  • class.getDeclaredField(FieldName):获取class类中的FieldName变量。

  • class.getDeclaredFields():获取class类中的所有变量。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//1. 获取该类的publicStr字段
Field field = cl.getField("publicStr");//只能获取public声明的变量,获取privateStr失败
System.out.println(field);
/*
输出:
public java.lang.String com.example.uu.Test.publicStr
*/
//2.获取该类中所有字段
Field[] declaredFields = cl.getDeclaredFields();
for(Field dec : declaredFields){
System.out.println(dec);
}
/*
public java.lang.String com.example.uu.Test.publicStr
private java.lang.String com.example.uu.Test.privateStr
com.test.wtf.Dog com.example.uu.Test.dog
*/

2.3.2 操作字段

  • field.getXxx(obj):获取obj对象的field字段的属性值。Xxx代指8个基本数据类型,如果该属性类型是引用类型则直接使用Field.get(obj)
  • field.setXxx(obj, value):将obj对象的Field字段赋值为valueXxx代指8个基本数据类型,如果该字段类型是引用类型则直接使用Field.set(obj, value)
  • field.setAccessible(bool):设置field字段的访问权限,若bool为true则表示取消字段的访问权限控制,这意味着private声明的字段也可以进行访问。

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//1.获取类
Class cl= Class.forName("com.example.uu.Test");
//2.获取构造函数
Constructor constructor = cl.getConstructor(String.class);
//3.创建类对象
Object newtest = constructor.newInstance("ousasf");
//4.获取privateStr字段
Field privateStr = cl.getDeclaredField("privateStr");
//5.因为该字段是Private权限,所以需要取消属性的访问权限控制
privateStr.setAccessible(true);
System.out.println(privateStr.get(newtest));
//6.修改privateStr字段的值
privateStr.set(newtest,"ahlsdfjpasp");
System.out.println(privateStr.get(newtest));
/*
输出:
abc
ahlsdfjpasp
*/

2.4 方法反射

2.4.1 获取方法

  • class.getMethod(MethodName,...ParameterTypes):获取class类中的public权限的方法,MethodName指定所要获取的方法的方法名,ParameterTypes指定所获取的方法中的参数的类型,没有则表示无参。
  • class.getMethods():获取class类中所有public权限的方法。
  • class.getDeclaredMethod(MethodName,...ParameterTypes):获取class类中任意方法。
  • class.getDeclaredMethods():获取class类的所有方法。

示例代码:

1
2
3
//获取带一个参数的且为int类型的getPublicStr方法
Method method = cl.getMethod("getPublicStr",int.class);
System.out.println(method);

2.4.2 执行方法

  • method.invoke(obj,...args):调用obj对象的method方法,args指定传入的参数,没有则表示无参。
  • method.setAccessible(bool):设置method方法的访问权限,若bool为true则表示取消方法的访问权限控制,这意味着private声明的方法也可以被调用。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//1.获取类
Class cl= Class.forName("com.example.uu.Test");
//2.获取带一个参数且为String类型的构造方法
Constructor constructor = cl.getConstructor(String.class);
//3.通过构造方法,构造类对象
Object newtest = constructor.newInstance("abcdedfg");
//4.获取getPublicStr()方法
Method method = cl.getDeclaredMethod("getPublicStr");
System.out.println(method);
//5.取消访问控制
//method.setAccessible(true);
//6.调用该方法
System.out.println(method.invoke(newtest));
/*
输出:
public java.lang.String com.example.uu.Test.getPublicStr()
abcdedfg
*/

参考:

Java反射机制-十分钟搞懂 - 知乎 (zhihu.com)


java反射技术学习
http://example.com/2023/11/23/Android安全/java反射技术学习/
作者
gla2xy
发布于
2023年11月23日
许可协议