Java 中反射的学习

Java 中反射的学习

反射是 Java 提供的一种机制,通过 java.lang.reflect 包中的接口和类,可以在运行时动态地获取类的结构信息(如构造器、成员变量、成员方法等),并对其进行操作。


什么是反射?

定义

反射是指将加载到内存中的字节码,通过代码编程的方式解析出类的各个组成部分(构造器、成员变量、成员方法)。

作用

反射的主要作用包括:

  • 动态加载类和操作类的成员。
  • 实现框架的通用性(如 Spring、Hibernate 等)。
  • 在运行时动态生成代理类。

如何获取 Class 对象?

在 Java 中,可以通过以下三种方式获取 Class 对象:

1. 通过类的 class 属性

每个类都有一个静态的 class 属性,可以直接通过 类名.class 获取对应的 Class 对象。

1
Class<?> clazz = String.class;

2. 通过对象的 getClass() 方法

每个 Java 对象都有一个 getClass() 方法,可以通过该方法获取对象所属类的 Class 对象。

1
2
String str = "Hello";
Class<?> clazz = str.getClass();

3. 通过 Class.forName() 方法

使用类的全限定名(包名+类名)作为参数,调用 Class.forName() 方法获取 Class 对象。

1
2
3
4
5
try {
Class<?> clazz = Class.forName("java.lang.String");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

注意:使用 Class.forName() 方法时,如果类不存在或类加载失败,会抛出 ClassNotFoundException


解析类的组成部分

通过反射,可以解析类的以下组成部分:

构造器:Constructor

获取构造器

  • getConstructors():获取类中所有的 公有构造器
  • getDeclaredConstructors():获取类中所有的构造器(包括私有构造器)。
1
2
3
4
5
6
7
Class<?> clazz = String.class;

// 获取所有公有构造器
Constructor<?>[] publicConstructors = clazz.getConstructors();

// 获取所有构造器(包括私有)
Constructor<?>[] allConstructors = clazz.getDeclaredConstructors();

调用构造器

通过 Constructor 对象的 newInstance() 方法,可以调用构造器创建对象。

1
2
3
4
5
6
7
8
9
10
try {
// 获取指定的构造器
Constructor<String> constructor = String.class.getConstructor(String.class);

// 调用构造器创建对象
String str = constructor.newInstance("Hello");
System.out.println(str); // 输出:Hello
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}

设置私有构造器可访问

对于私有构造器,可以通过 setAccessible(true) 方法设置其可访问性。

1
2
3
4
5
6
7
8
9
10
11
12
13
try {
// 获取私有构造器
Constructor<String> privateConstructor = String.class.getDeclaredConstructor(byte[].class);

// 设置可访问
privateConstructor.setAccessible(true);

// 调用私有构造器创建对象
String str = privateConstructor.newInstance("Hello".getBytes());
System.out.println(str); // 输出:Hello
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}

成员变量:Field

通过反射,可以获取类的成员变量(包括公有和私有)。

获取成员变量

  • getFields():获取类中所有的 公有成员变量
  • getDeclaredFields():获取类中所有的成员变量(包括私有成员变量)。
1
2
3
4
5
6
7
Class<?> clazz = String.class;

// 获取所有公有成员变量
Field[] publicFields = clazz.getFields();

// 获取所有成员变量(包括私有)
Field[] allFields = clazz.getDeclaredFields();

操作成员变量

通过 Field 对象,可以读取或修改成员变量的值。

1
2
3
4
5
6
7
8
9
10
11
12
try {
Field valueField = String.class.getDeclaredField("value");

// 设置私有成员变量可访问
valueField.setAccessible(true);

String str = "Hello";
char[] value = (char[]) valueField.get(str);
System.out.println(Arrays.toString(value)); // 输出:[H, e, l, l, o]
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}

成员方法:Method

通过反射,可以获取类的成员方法(包括公有和私有)。

获取成员方法

  • getMethods():获取类中所有的 公有方法
  • getDeclaredMethods():获取类中所有的方法(包括私有方法)。
1
2
3
4
5
6
7
Class<?> clazz = String.class;

// 获取所有公有方法
Method[] publicMethods = clazz.getMethods();

// 获取所有方法(包括私有)
Method[] allMethods = clazz.getDeclaredMethods();

调用成员方法

通过 Method 对象的 invoke() 方法,可以调用类的方法。

1
2
3
4
5
6
7
8
9
try {
Method charAtMethod = String.class.getMethod("charAt", int.class);

String str = "Hello";
char ch = (char) charAtMethod.invoke(str, 1);
System.out.println(ch); // 输出:e
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}