什么是反射?反射允许对封装类的字段,方法和构造函数的信息进行编程访问。

获取class对象的三种方式

  1. Class.forName(“全类名”);//全类名:包名+类名
  2. 类名.class;//这种方式一般当作参数传递
  3. 对象.getClass();//当已经有了这个类的对像时使用

在Java中,万物即可为对象,如:
获取Class对象:Class
构造方法:Constructor
字段(成员变量):Field
成员方法:Method

利用反射获取构造方法

Class类中用于获取构造方法的方法
Constructor<?>[] getConstructors():返回所有公共构造方法对象的数组
Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组
Constructor getConstructor(Class<?>… parameterTypes):返回单个公共构造方法对象
Constructor getDeclaredConstructor(Class<?>… parameterTypes):返回单个构造方法对象

Constructor类中用于创建对象的方法
T newInstance(Object.. initargs):根据指定的构造方法创建对象
setAccessible(boolean flag):设置为true, 表示取消访问检查

获取构造方法示例代码

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
public class Student {
private String name;
private int age;

public Student(String name, int age) {
this.name = name;
this.age = age;
}

public Student() {
}

protected Student(int age) {
this.age = age;
}
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

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

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
public class Main {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//获取字节码文件
Class<?> student = Class.forName("org.example.Student");
//所有公共构造方法
Constructor<?>[] con1 = student.getConstructors();
for (int i = 0; i < con1.length; i++) {
System.out.println(con1[i]);
//public org.example.Student()
//public org.example.Student(java.lang.String,int)
}
//所有构造方法
Constructor<?>[] con2 = student.getDeclaredConstructors();
for (int i = 0; i < con2.length; i++) {
System.out.println(con2[i]);
//protected org.example.Student(int)
//public org.example.Student()
//public org.example.Student(java.lang.String,int)
}

//返回单个构造方法对象
Constructor<?> con3 = student.getDeclaredConstructor( int.class);
System.out.println(con3);
//protected org.example.Student(int)

//取消访问检查
con3.setAccessible(true);
Student std = (Student) con3.newInstance(18);
System.out.println(std);
//Student{name='null', age=18}
}
}

利用反射获取成员变量

Field[] getFields():返回所有公共成员变量对象的数组
Field[] getDeclaredFields():返回所有成员变量对象的数组
Field getField(String name):返回单个公共成员变量对象
Field getDeclaredField(String name):返回单个成员变量对象

Field类中用于创建对象的方法
void set(Object obj, Object value):赋值
Object get(Object obj)获取值。

获取成员变量示例代码

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
package org.example;

public class Student {
private String name;
private int age;
public String major;

public Student(String name, int age, String major) {
this.name = name;
this.age = age;
this.major = major;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getMajor() {
return major;
}

public void setMajor(String major) {
this.major = major;
}
}

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
package org.example;

import java.lang.reflect.Field;

public class Main {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
//获取字节码文件
Class<?> classzz = Class.forName("org.example.Student");
//获取所有成员变量
Field[] fields = classzz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
//private java.lang.String org.example.Student.name
//private int org.example.Student.age
//public java.lang.String org.example.Student.major
//获取成员变量的名字
System.out.println(field.getName());
//name
//age
//major
//获取成员变量的数据类型
System.out.println(field.getType());
//class java.lang.String
//int
//class java.lang.String
}

//获取指定的单个成员变量
Field name = classzz.getDeclaredField("name");
System.out.println(name);
//private java.lang.String org.example.Student.name

//获取权限修饰符
int modifiers = name.getModifiers();
System.out.println(modifiers);//2 2代表private

//获取对象成员变量记录的值
Student student = new Student("张三", 20, "计算机");
name.setAccessible(true);//临时取消访问权限
Object value = name.get(student);
System.out.println(value);//张三

//修改对象成员变量记录的值
name.set(student, "李四");
System.out.println(student.getName());//李四
}
}

利用反射获取成员方法

Class类中用于获取成员方法的方法
Method[] getMethods():返回所有公共成员方法对象的数组,包括继承的
Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
Method getMethod(String name, Class<?>… parameterTypes):返回单个公共成员方法对象
Method getDeclaredMethod(String name, Class<?>… parameterTypes):返回单个成员方法对像

Method类中用于创建对象的方法
Object invoke(Object obj, Object… args):运行方法
参数一:用obj对象调用该方法
参数二:调用方法的传递的参数(如果没有就不写)
返回值:方法的返回值(如果没有就不写)

获取成员方法示例代码

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
package org.example;

import java.io.IOException;

public class Student {
private String name;
private int age;

public void sleep(){//公共睡觉方法
System.out.println("Student is sleeping");
}

private String eating(String food) throws IOException {//私有吃饭方法
System.out.println("Student is eating " + food);
return "奥里给";
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}



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

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
package org.example;

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

public class Main {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//获取字节码对象文件
Class<?> classzz = Class.forName("org.example.Student");
//获取所有公共方法(包括父类中的)
Method[] methods = classzz.getMethods();
for (int i = 0; i < methods.length; i++) {
System.out.println(methods[i]);
//public java.lang.String org.example.Student.getName()
//public java.lang.String org.example.Student.toString()
//public void org.example.Student.sleep()
//public void org.example.Student.setName(java.lang.String)
//public int org.example.Student.getAge()
//public void org.example.Student.setAge(int)
//public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
//public final void java.lang.Object.wait() throws java.lang.InterruptedException
//public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
//public boolean java.lang.Object.equals(java.lang.Object)
//public native int java.lang.Object.hashCode()
//public final native java.lang.Class java.lang.Object.getClass()
//public final native void java.lang.Object.notify()
//public final native void java.lang.Object.notifyAll()
}
//获取所有的方法(不包括父类中的)
Method[] declaredMethods = classzz.getDeclaredMethods();
for (int i = 0; i < declaredMethods.length; i++) {
System.out.println(declaredMethods[i]);
//public java.lang.String org.example.Student.getName()
//public java.lang.String org.example.Student.toString()
//public void org.example.Student.sleep()
//public void org.example.Student.setName(java.lang.String)
//public int org.example.Student.getAge()
//private void org.example.Student.eating(java.lang.String)
//public void org.example.Student.setAge(int)
}

// 获取指定的单一方法(方法名 + 参数 )
Method m = classzz.getDeclaredMethod("eating", String.class);
System.out.println(m);
//private void org.example.Student.eating(java.lang.String)

//获取方法的修饰符
int modifiers = m.getModifiers();
System.out.println(modifiers);//2 表示private

//获取方法的名字
String name = m.getName();
System.out.println(name);//eating

//获取方法的形参
Parameter[] parameters = m.getParameters();
for (int i = 0; i < parameters.length; i++) {
System.out.println(parameters[i]);
//java.lang.String arg0
}

//获取方法的抛出异常
Class<?>[] exceptionTypes = m.getExceptionTypes();
for (int i = 0; i < exceptionTypes.length; i++) {
System.out.println(exceptionTypes[i]);
//class java.io.IOException
}

// 方法运行 invoke
Student student = new Student();
m.setAccessible(true);// 暴力反射
// 第一个参数是调用的对象,后面的是方法的参数
Object result = m.invoke(student, "apple");//Student is eating apple
System.out.println(result);//奥里给
}
}

场景应用

获取对象的成员变量名和值,并写到文件中

1
2
3
4
5
6
7
8
9
10
11
public class Student {
private String name;
private int age;
private String sex;

public Student(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
}
1
2
3
4
5
6
7
8
9
public class Teacher {
private String name;
private String salary;

public Teacher(String name, String salary) {
this.name = name;
this.salary = salary;
}
}
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
package org.example;


import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;

public class Main {
public static void main(String[] args) throws IllegalAccessException, IOException {
Student student = new Student("张三", 20, "男");
Teacher teacher = new Teacher("王老师", "8000");

printInfo(teacher);
}

public static void printInfo(Object object) throws IllegalAccessException, IOException {
//获取字节码文件
Class<?> clazz = object.getClass();

//创建IO流
BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));

//获取属性
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
field.setAccessible(true);//设置私有属性可访问
//获取属性的名称
String name = field.getName();
//获取属性的值
Object value = field.get(object);
//写出数据
bw.write(name + "=" + value);
bw.newLine();
}

bw.close();
}
}

利用反射,根据配置文件来动态的创建对象,并调用方法

在当前src目录下有pro.properties配置文件,其中内容如下
classname=org.example.xnj.Student
method=study

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 org.example.xnj;

public class Student {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
this.name = name;
this.age = age;
}

public void study(){
System.out.println("student is studying");
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

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

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 org.example.xnj;

public class Teacher {
private String name;
private double salary;

public Teacher() {
}

public Teacher(String name, double salary) {
this.name = name;
this.salary = salary;
}

public void teach(){
System.out.println("teacher is teaching");
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public double getSalary() {
return salary;
}

public void setSalary(double salary) {
this.salary = salary;
}

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

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
package org.example.xnj;

import java.io.FileInputStream;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//读取配置文件信息
Properties prop = new Properties();
//创建io流
FileInputStream fis = new FileInputStream("src/pro.properties");
prop.load(fis);
System.out.println(prop);//{classname=org.example.xnj.Student, method=study}

//获取全类名和方法名
String classname = (String) prop.get("classname");
String methodName = (String) prop.get("method");

//利用反射创建对象并运行方法
Class<?> aClass = Class.forName(classname);

//获取构造方法
Constructor con = aClass.getDeclaredConstructor();
//创建对象
Object o = con.newInstance();
System.out.println(o);//Student{name='null', age=0}

//获取成员方法
Method method = aClass.getDeclaredMethod(methodName);
method.setAccessible(true);//临时取消检验

method.invoke(o);//student is studying
}
}

之后改变配置文件的值就能改变不同的类调用方法。