反射和动态管理(二十一-完)


反射和动态管理(二十一-完)

反射

反射允许对字段(成员变量),成员方法,构造方法的信息进行编程访问。

反射操作可分为获取解刨

获取不是从java文件获取,而是从class字节码文件获取。

作用

  1. 获取一个类里面的所有的信息,获取到了后,再执行其他的业务逻辑
  2. 结合配置文件,动态的创建对象并调用方法

获取class对象

  1. Class.forname(“全类名”)
    • 全类名:包名+类名‘
    • 该方法是最为常用的
  2. 类名.class
    • 一般当做当前参数进行传递,比如synchronized(类名.class)
  3. 对象.getclass
    • 有该类的对象后,才可使用

范例

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

public Student() {
}

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

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

/**
* 获取
* @return age
*/
public int getAge() {
return age;
}

/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}

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

//Test.java
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Class class1 = Class.forName("reflect.Student");
System.out.println(class1);
Class class2 = Student.class;
System.out.println(class2);
Student student=new Student();
Class class3=student.getClass();
System.out.println(class3);
System.out.println(class1==class2);
System.out.println(class2==class3);
}
}
/*
class reflect.Student
class reflect.Student
class reflect.Student
true
true
*/

获取构造方法

Class类中用于获取构造方法的方法

getConstructors

Constructor<?>[] getConstructors()

说明:返回所有公共构造方法对象的数组

getDeclaredConstructors

Constructor<?>[] getDeclaredConstructors()

说明:返回所有构造方法对象的数组

getConstructor

Constructor getConstructor(Class<?>…parameterTypes)

说明:返回单个公共构造方法对象

getDeclaredConstructor

Constructor getDeclaredConstructor(Class<?>…parameterTypes)

说明:返回单个构造方法对象

Constructor类中用于创建对象的方法

newInstance

T newInstance(Object…initargs)

说明:根据指定的构造方法创建对象

setAccessible

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
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//Student.java
public class Student {
private String name;
private int age;

public Student() {
}

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

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

/**
* 获取
* @return age
*/
public int getAge() {
return age;
}

/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}

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

//Test.java
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;

public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class clazz = Class.forName("reflect.Student");
//getConstructors
Constructor[] constructors1 = clazz.getConstructors();
for (Constructor constructor:constructors1){
System.out.println(constructor);
}
System.out.println();

//getDeclaredConstructors
Constructor[] constructors2 = clazz.getDeclaredConstructors();
for (Constructor constructor:constructors2){
System.out.println(constructor);
}
System.out.println();

//getConstructor
Constructor constructor1 = clazz.getConstructor();
System.out.println(constructor1);
System.out.println();

//getDeclaredConstructor
Constructor constructor2 = clazz.getDeclaredConstructor(String.class,int.class);
System.out.println(constructor2);
System.out.println();


System.out.println(constructor2.getModifiers());//获取权限修饰符,以数字的形式表现
System.out.println();
Parameter[] parameters = constructor2.getParameters();//获取参数
for (Parameter parameter:parameters){
System.out.println(parameter);
}
//newInstance和setAccessible
//暴力反射:临时取消权限校验
constructor2.setAccessible(true);//使private类型的构造方法可以创建
Student student=(Student) constructor2.newInstance("张三",3);
System.out.println(student);
}
}
/*
public reflect.Student(java.lang.String)
public reflect.Student()

protected reflect.Student(int)
private reflect.Student(java.lang.String,int)
public reflect.Student(java.lang.String)
public reflect.Student()

public reflect.Student()

private reflect.Student(java.lang.String,int)

2

java.lang.String arg0
int arg1
Student{name = 张三, age = 3}

*/

获取成员变量

Class类中获取成员变量对象的方法

getFields

Field[] getFields()

说明:返回所有公共成员变量对象的数组

getDeclaredFields

Field[] getDeclaredFields()

说明:返回所有成员变量对象的数组

getField

Field getField(String name)

说明:返回单个公共成员变量对象

getDeclaredField

Field getDeclaredField(String name)

说明:返回单个成员变量对象

Field类中用于创建对象的方法

set

void set(Object obj,Object value)

说明:赋值

get

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

public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Class clazz=Class.forName("reflect.Student");
//getFields
Field[] fields1 = clazz.getFields();
for (Field field:fields1){
System.out.println(field);
}
System.out.println();

//getDeclaredFields
Field[] fields2 = clazz.getDeclaredFields();
for (Field field:fields2){
System.out.println(field);
}
System.out.println();

//getField
Field field1=clazz.getField("sex");
System.out.println(field1);
System.out.println();

//getDeclaredField
Field field2=clazz.getDeclaredField("name");
System.out.println(field2);
System.out.println();

//get
System.out.println(field1.getModifiers());//获取变量修饰符
System.out.println(field1.getName());//获取变量名
Class<?> type = field1.getType();//获取变量类型
System.out.println(type);
System.out.println();

Student student=new Student("张三",18,"男");
field2.setAccessible(true);
String s=(String)field2.get(student);
System.out.println(s);
System.out.println();

field2.set(student,"李四");
System.out.println(student);
}
}
/*
public java.lang.String reflect.Student.sex

private java.lang.String reflect.Student.name
private int reflect.Student.age
public java.lang.String reflect.Student.sex

public java.lang.String reflect.Student.sex

private java.lang.String reflect.Student.name

1
sex
class java.lang.String

张三

Student{name = 李四, age = 18, sex = 男}

*/

获取成员方法

Class类中用于获取成员方法的方法

getMethods

Method[] getMethods()

说明:返回所有公共成员方法对象的数组,包括继承的

getDeclaredMethods

Method[] getDeclaredMethods()

说明:返回所有成员方法对象的数组,不包括继承的

getMethod

Method getMethods(String name,Class<?>…parameterTypes)

说明:返回单个公共成员方法对象

getDeclaredMethod

Method getDeclaredMethods(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
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//Test.java
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz=Class.forName("reflect.Student");
//getMethods
Method[] methods1 = clazz.getMethods();
for (Method method:methods1){
System.out.println(method);
}
System.out.println();

//getDeclaredMethods
Method[] methods2=clazz.getDeclaredMethods();
for(Method method:methods2){
System.out.println(method);
}
System.out.println();

//getMethod
Method study = clazz.getMethod("study", String.class);
System.out.println(study);
System.out.println();

//getMethods
Method eat = clazz.getDeclaredMethod("eat", String.class,String.class);
System.out.println(eat);
System.out.println();

System.out.println(eat.getModifiers());//获取修饰符
System.out.println(eat.getName());//获取名字
Parameter[] parameters = eat.getParameters();
for (Parameter parameter:parameters){
System.out.println(parameter);
}

Class[] exceptionTypes = study.getExceptionTypes();
for (Class ex:exceptionTypes){
System.out.println(ex);
}
System.out.println();

Student student=new Student("路人甲",8);
eat.setAccessible(true);
String result=(String)eat.invoke(student,"汉堡包","可乐");
System.out.println(result);
}
}
//Student
import java.io.IOException;

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

public Student() {
}

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


private String eat(String food,String drink){
System.out.println(name+"正在吃"+food+",正在喝"+drink);
return "排泄物";
}
private String eat(String food){
System.out.println(name+"正在吃"+food);
return "排泄物";
}
public void study(String name)throws IOException,ArrayIndexOutOfBoundsException {
System.out.println(name+"正在学习");
}

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

/**
* 获取
* @return age
*/
public int getAge() {
return age;
}

/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}

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

/*
public java.lang.String reflect.Student.toString()
public java.lang.String reflect.Student.getName()
public void reflect.Student.setName(java.lang.String)
public int reflect.Student.getAge()
public void reflect.Student.setAge(int)
public void reflect.Student.study(java.lang.String) throws java.io.IOException,java.lang.ArrayIndexOutOfBoundsException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) 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()

public java.lang.String reflect.Student.toString()
public java.lang.String reflect.Student.getName()
public void reflect.Student.setName(java.lang.String)
public int reflect.Student.getAge()
public void reflect.Student.setAge(int)
private java.lang.String reflect.Student.eat(java.lang.String)
private java.lang.String reflect.Student.eat(java.lang.String,java.lang.String)
public void reflect.Student.study(java.lang.String) throws java.io.IOException,java.lang.ArrayIndexOutOfBoundsException

public void reflect.Student.study(java.lang.String) throws java.io.IOException,java.lang.ArrayIndexOutOfBoundsException

private java.lang.String reflect.Student.eat(java.lang.String,java.lang.String)

2
eat
java.lang.String arg0
java.lang.String arg1
class java.io.IOException
class java.lang.ArrayIndexOutOfBoundsException

路人甲正在吃汉堡包,正在喝可乐
排泄物
*/

范例

例1

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
//对于任意一个对象,都可以吧对象的所有字段名和值,保存到文件中去
//Test.java
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;

public class Test {
public static void main(String[] args) throws IOException, IllegalAccessException {
Student s=new Student("张三",18);
Teacher t=new Teacher("李四",19999.0,3,11);
//saveFile(t);
//saveFIle(s)

}
public static void saveFile(Object obj) throws IOException, IllegalAccessException {
BufferedWriter bw=new BufferedWriter(new FileWriter("a.txt"));
Class clazz = obj.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field:fields){
field.setAccessible(true);
String name = field.getName();
Object value = field.get(obj);
bw.write(name+"="+value);
bw.newLine();
}
bw.close();
}
}

//Student.java
public class Student {
private String name;
private int age;

public Student() {
}

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

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

/**
* 获取
* @return age
*/
public int getAge() {
return age;
}

/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}

public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
//Teacher.java
public class Teacher {
private String name;
private double salary;
private int id;
private int age;

public Teacher() {
}

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

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

/**
* 获取
* @return salary
*/
public double getSalary() {
return salary;
}

/**
* 设置
* @param salary
*/
public void setSalary(double salary) {
this.salary = salary;
}

/**
* 获取
* @return id
*/
public int getId() {
return id;
}

/**
* 设置
* @param id
*/
public void setId(int id) {
this.id = id;
}

/**
* 获取
* @return age
*/
public int getAge() {
return age;
}

/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}

public String toString() {
return "Teacher{name = " + name + ", salary = " + salary + ", id = " + id + ", age = " + age + "}";
}
}
/*
若是执行saveFile(t)
a.txt内容为
name=李四
salary=19999.0
id=3
age=11

*/
/*
若是执行saveFile(s)
a.txt内容为
name=张三
age=18

*/

例2

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
//反射可以跟配置文件结合的方式,动态的创建对象,并调用方法
/*properties.properties
classname=reflect.Teacher
method=teach
*/
//Student.java
public class Student {
private String name;
private int age;

public Student() {
}

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

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

/**
* 获取
* @return age
*/
public int getAge() {
return age;
}

/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}

public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
public void study(){
System.out.println("学习");
}
}
//Teacher.java
public class Teacher {
private String name;
private double salary;
private int id;
private int age;

public Teacher() {
}

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

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

/**
* 获取
* @return salary
*/
public double getSalary() {
return salary;
}

/**
* 设置
* @param salary
*/
public void setSalary(double salary) {
this.salary = salary;
}

/**
* 获取
* @return id
*/
public int getId() {
return id;
}

/**
* 设置
* @param id
*/
public void setId(int id) {
this.id = id;
}

/**
* 获取
* @return age
*/
public int getAge() {
return age;
}

/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}

public String toString() {
return "Teacher{name = " + name + ", salary = " + salary + ", id = " + id + ", age = " + age + "}";
}
public void teach(){
System.out.println("教学");
}
}
//Test.java
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 Test {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Properties pro=new Properties();
FileInputStream fis = new FileInputStream("properties.properties");
pro.load(fis);
fis.close();
String name=(String) pro.get("classname");
String method=(String)pro.get("method");
Class clazz=Class.forName(name);
Constructor constructor = clazz.getDeclaredConstructor();
Object o = constructor.newInstance();
System.out.println(o);

Method method1 = clazz.getDeclaredMethod(method);
method1.setAccessible(true);
method1.invoke(o);
}
}
/*
Teacher{name = null, salary = 0.0, id = 0, age = 0}
教学
*/

动态代理

代理可以无侵入式(不改变原有代码)的给对象增强其他功能。

对象若嫌身上干的事太多,可通过代理转移部分职责。

对象若有方法要被代理,代理则一定要有对应的方法。

调用者调用对象的方法时,是由调用者先调用代理的方法,再由代理调用对象的方法。

代理长什么样:代理里面是对象要被代理的方法。

java通过接口保证代理的样子,后面的对象和代理需要实现同一个接口,接口中就是被代理的所有方法。

Proxy

java.lang.reflect.Proxy类:提供为对象产生代理对象的方法:

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

参数一:用于指定用哪个类加载器,去加载生成的代理类

参数二:指定接口,这些接口用于指定生成的代理长什么样,也就是有哪些方法

参数三:用来指定生成的代理对象要干什么事情

范例

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
//Cinema.java
public class Cinema implements CinemaExtend{
private String name;

public Cinema() {
}

@Override
public String watchMovie(){
System.out.println("进入"+name+"电影院");
return "看电影";
}
@Override
public void eatPopcorn(String audience){
System.out.println(audience+"吃爆米花");
}

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

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

public String toString() {
return "Cinema{name = " + name + "}";
}
}
//CinemaExtend.java
public interface CinemaExtend {
public abstract String watchMovie();
public abstract void eatPopcorn(String audience);
}
//ProxyUtil.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyUtil {
public static CinemaExtend createProxy(Cinema cinema){
CinemaExtend cinemaExtend=(CinemaExtend)Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
new Class[]{CinemaExtend.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("watchMovie".equals(method.getName())){
System.out.println("买电影票");
}else if("eatPopcorn".equals(method.getName())){
System.out.println("买爆米花");
}
return method.invoke(cinema,args);
}
});
return cinemaExtend;
}
}
//Test.java
public class Test {
public static void main(String[] args) {
Cinema cinema=new Cinema("万达");
CinemaExtend ce=ProxyUtil.createProxy(cinema);
ce.eatPopcorn("路人甲");

System.out.println();
System.out.println(ce.watchMovie());
}
}
/*
买爆米花
路人甲吃爆米花

买电影票
进入万达电影院
看电影
*/

Author: ljs
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source ljs !
评论
  TOC