Java - 反射机制

基本概念

  • 通常情况下编写代码都是固定的,无论运行多少次执行的结果也是固定的,在某些特殊场合中编写代码时不确定要创建什么类型的对象,也不确定要调用什么样的方法,这些都希望通过运行时传递的参数来决定,该机制叫做动态编程技术,也就是反射机制。
  • 通俗来说,反射机制就是用于动态创建对象并且动态调用方法的机制。
  • 目前主流的框架底层都是采用反射机制实现的。
  • 如:
    Person p= new Person (); // 表示声明 Person 类型的引用指向 Person 类型的对象
    p.show (); // 表示调用 Person 类中的成员方法 show

Class 类

甚本概念

  • java.lang.Class 类的实例可以用于描述 java 应用程序中的类和接口,也就是一种数据类型。
  • 该类没有公共构造方法,该类的实例由 java 虚拟机和类加载器自动构造完成,本质上就是加载到内存中的运行时类。

获取 Class 对象的方式

  • 使用数据类型.class 的方式可以获取对应类型的 Class 对象
  • 使用引用 / 对象.getClass() 的方式可以获取对应类型的 Class 对象。
  • 使用包装类.TYPE 的方式可以获取对应基本数据类型的 Class 对象
  • 使用 Class.forName 的方式来获取参数指定类型的 Class 象
  • 使用类加载器 ClassLoader 的方式获取指定类型的 Class 对象

常用方法

方法声明功能介绍
static Class< ? > forName(String className)用于获取参数指定类型对应的 class 对象并返回
T newInstance()(已过时 请使用 Constructor 类) 用于创建该 Cass 对象所表示类的新实例

Constructor 类

基本概念

  • java.lang.reflect.Constructor 类主要用于描述获取到的构造方法信息。

Class 类的常用方法

方法声明功能介绍
Constructor< T > getConstructor( Class< ? >…parrmeterTypes)用于获取此 Class 对象所表示类型中参数指定的公共构造方法
Constructor< ? > [] getConstructors()用于获取此 Class 对象所表示类型中所有的公共构造

Constructor 类的常用方法

方法声明功能介绍
T newInstance(object…initargs)使用此 Constructor 对象描述的构造方法来构造 Cass 对象代表类型的新实例
int getModifiers()获取方法的访问修饰符
String getName()获取方法的名称
Class< ? >[] getParameterType()获取方法所有参数的类型

使用反射机制创建实例

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
import java.io.*;
import java.lang.reflect.Constructor;

public class PersonTest {
public static void main(String[] args) {
FileInputStream fis = null;
InputStreamReader isr = null;
BufferedReader br = null;
try {
// 文件字节输入流
fis = new FileInputStream("./config.txt");
// 将文件字节输入流转换为 Reader 输入流
isr = new InputStreamReader(fis);
// 使用字符缓冲加载输入流
br = new BufferedReader(isr);
// 获取配置文件第一行
String line = br.readLine();
// 将配置文件中的类动态加载
Class forName = Class.forName(line);
System.out.println("动态加载的类为:" + forName); // class task4.reflect.Person
// 获取Class对象的无参构造方法,也就是Person的无参构造方法
Constructor constructor = forName.getConstructor();
// 使用获取到的无参构造方法构造相应类型的对象也就是Person类型的对象
System.out.println("使用无参构造的对象是:" + constructor.newInstance());
// 通过有参构造获取对象 按传入参数选择对应的构造
Constructor constructor1 = forName.getConstructor(int.class, String.class);
System.out.println("使用有参构造获取到的对象是:" + constructor1.newInstance(10,"feng"));

} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != fis) {
fis.close();
}
if (null != isr) {
isr.close();
}
if (null != br) {
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}

}

}
}

Field 类

基本概念

java.lang.reflect.Field 类主要用于描述获取到的单个成员变量信息。

Class 类的常用方法

方法声明功能介绍
Field getDeclaredField(String name)用于获取此 Cas 对所表示类中参数指定的单个成员变量信息
Field getDeclaredFields()用于获取此 Class 对象所表示类中所有成员变量信息

Field 类的常用方法

方法声明功能介绍
Object get(Object obj)取参数对象 Object 中此 Field 对象所表示成员变量的数值
void set(Object obj, Object value)将参数对象 Object 中此 Field 对象表示成员变量的数值修改为参数 vlaue 的数值
void setAccessible(boolean flag)当实参传通 true 时,则反射对象在使用时应该取消 Java 语言访问检查
int getModifiers()获取成员变量的访问修饰符
Class< ? > getType()获取成员变量的数据类型
String getName()取成员变量的名称

获取和修改成员变量

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
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

public class PersonTest {
public static void main(String[] args) {
FileInputStream fis = null;
InputStreamReader isr = null;
BufferedReader br = null;
try {
// 文件字节输入流
fis = new FileInputStream("./config.txt");
// 将文件字节输入流转换为 Reader 输入流
isr = new InputStreamReader(fis);
// 使用字符缓冲加载输入流
br = new BufferedReader(isr);
// 获取配置文件第一行
String line = br.readLine();
// 将配置文件中的类动态加载
Class forName = Class.forName(line);
// 通过有参构造获取对象 按传入参数选择对应的构造
Constructor constructor1 = forName.getConstructor(int.class, String.class);
System.out.println("使用有参构造获取到的对象是:" + constructor1.newInstance(10, "feng"));

// 有参构造创建对象
Object object = constructor1.newInstance(10, "feng");
// 获取成员变量
Field field = forName.getDeclaredField("name");
// 获取对象 object 中名字为 filed 的数值,也就是成员变量name中的值
// 如果是private没有权限访问 异常,需要反射时调用setAccessible(true);取消java访问检查
field.setAccessible(true); // 取消 java 访问检查
Object v = field.get(object);
System.out.println("获取到成员变量的值为:" + v);

// 修改成员变量
field.set(object, "li");
v = field.get(object);
System.out.println("修改后的成员变量值为:" + v);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != fis) {
fis.close();
}
if (null != isr) {
isr.close();
}
if (null != br) {
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}

}

}
}

Method 类

基本概念

java.lang.reflect.Method 类主要用于描述获取到的个成员方法信息。

Class 类的常用方法

方法声明功能介绍
Method getMethod(String name, Class< ? >…parameterTypes)用于获取该 Class 对象表示类中名字为 name 参数为 parameterTypes 的指定公共成员方法
Method getMethods()用于获取该 Cass 对象表示类中所有公共成员方法

Method 类的常用方法

方法声明功能介绍
Object invoke(Object obj, Object…args)使用对象 obj 来调用此 Method 对象所表示的成员方法,实参传递 args
int getModifiers()获取方法的访问修饰符
Class< ? > getReturnType()获取方法的返回值类型
String getName()获取方法的名称
Class< ? > getParameterTypes()获取方法所有参数的类型
Class< ? > getExceptionTypes()获取方法的异常信息

获取方法及调用方法

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
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class PersonTest {
public static void main(String[] args) {
FileInputStream fis = null;
InputStreamReader isr = null;
BufferedReader br = null;
try {
// 文件字节输入流
fis = new FileInputStream("./config.txt");
// 将文件字节输入流转换为 Reader 输入流
isr = new InputStreamReader(fis);
// 使用字符缓冲加载输入流
br = new BufferedReader(isr);
// 获取配置文件第一行
String line = br.readLine();
// 将配置文件中的类动态加载
Class forName = Class.forName(line);
// 通过有参构造获取对象 按传入参数选择对应的构造
Constructor constructor1 = forName.getConstructor(int.class, String.class);
System.out.println("使用有参构造获取到的对象是:" + constructor1.newInstance(10, "feng"));

// 有参构造创建对象
Object object = constructor1.newInstance(10, "feng");
// 获取方法有参方法
Method setName = forName.getMethod("setName", String.class);
// 获取无参方法
Method getName = forName.getMethod("getName");
// 调用方法
setName.invoke(object, "Hello");
Object invoke = getName.invoke(object);
System.out.println("获取到的值为:" + invoke);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != fis) {
fis.close();
}
if (null != isr) {
isr.close();
}
if (null != br) {
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}

}

}
}

获取其它结构信息

方法声明功能介绍
Package getPackage()获取所在的包信息
Class< ? super T > getSuperClass()获取继承的父类信息
Class< ? >[] getInterfaces()获取实现的所有接口
Annotation[] getAnnotations()获取注解信息
Type[] getGenericInterfaces()获取泛型信息