天师

天下事有难易乎?为之,则难者亦易矣;不为,则易者亦难矣。


  • 首页

  • 分类

  • 归档

  • 标签

  • 关于

反射笔记

发表于 2018-04-09 分类于 笔记
本文字数: 13k 阅读时长 ≈ 12 分钟

反射

1. 反射定义:

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

(总结) 反射就是把java类中的各种成分映射成一个个的Java对象

2. 泛型问题系列:(摘自码农每日一题)

List 与 List 原始类型之间的区别?

主要区别有两点。

  • 原始类型和带泛型参数类型 之间的主要区别是在编译时编译器不会对原始类型进行类型安全检查,却会对带参数的类型进行检查,通过使用 Object 作为类型可以告知编译器该方法可以接受任何类型的对象(比如 String 或 Integer)。
  • 我们可以把任何带参数的类型传递给原始类型 List,但却不能把 List 传递给接受 List 的方法,因为会产生编译错误。

简单说说 List 与 List<?> 类型之间的区别?

List 是一个未知类型的 List,而 List 其实是任意类型的 List,我们可以把 List、List 赋值给 List,却不能把 List 赋值给 List。譬如:

  1. List<?> listOfAnyType;
  2. List<Object> listOfObject = new ArrayList<Object>();
  3. List<String> listOfString = new ArrayList<String>();
  4. List<Integer> listOfInteger = new ArrayList<Integer>();
  5. listOfAnyType = listOfString; //legal
  6. listOfAnyType = listOfInteger; //legal
  7. listOfObjectType = (List<Object>) listOfString; //compiler error

其他

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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
package com.zwang.april;

import com.zwang.april.bean.Student;
import com.zwang.april.bean.WorkMan;

import org.junit.Test;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
* ●●●
* 反射的概述:
* <p>
* JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,
* 都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
* 要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
* <p>
* (总结) 反射就是把java类中的各种成分映射成一个个的Java对象
* <p>
* ●●●
* 深拷贝 与 浅拷贝 : 大部分都是浅拷贝(通过实现Cloneable接口,重写clone()方法,调用super.clone()来实现深拷贝)
* 真正的深拷贝:通过实现Serializable 接口并用对象的序列化和反序列化来实现真正的深度克隆做法:(参阅下列的 clone())
* 通过ByteArrayOutputStream ObjectArrayOutputStream write() 再通过ByteArrayInputStream ObjectArrayInputStream read()实现
* <p>
* ●●●
* 泛型的协变 与 逆变 : 协变---> List<? extends Number> list = new ArrayList<>(); 逆变 ---> List<? super Number> list =new ArrayList<>();
* <p>
* 泛型的上边界 与 下边界 : ? extends Number 指定了上边界 ? super Number 指定了下边界
* <p>
* description: 练习处
* author: phl
* date: 2018-04-09 下午 2:06
* update:
* version: 1.0
*/
public class MainActivityTest {


/**
* 1 获取类名三种方式:
* 1.1 通过对象 getClass()
* 1.2 通过对象 .class
* 1.3 通过包名全路径 Class.forName(String package)
*/
@Test
public void test() {

//1.1 获取类名 (创建一个对象实例,然后通过getClass()方法获取---对象都已经拿到了,反射用处不大)
Student stu = new Student();
Class<? extends Student> aClass1 = stu.getClass();
System.out.println(aClass1.getName());

//1.2 获取类名 (通过 .class --- 需要导入包,依赖性较强)
Class<Student> aClass2 = Student.class;
System.out.println(aClass1 == aClass2);

try {
//1.3 获取类名(通过包名全路径+Class --- 一个字符串就可以,相对于更加优势)
Class<?> aClass3 = Class.forName("com.zwang.april.bean.Student");
System.out.println(aClass1 == aClass3);

Class<?> aClass = Class.forName("java.util.ArrayList");
System.out.print(aClass.getName());

} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}


/**
* 2 通过Class对象获取构造方法,成员变量,成员方法,并访问成员
* <p>
* 2.1 通过Class对象获取构造方法
* 批量
* class.getConstructors() 获取该所有public修饰的Constructor
* 单个
* class.getConstructor(Class... parameterTypes) 获取指定的public修饰的构造方法
* 批量
* class.getDeclaredConstructors() 获取所有的Constructor
* 单个
* class.getDeclaredConstructors(Class... parameterTypes) 获取指定的Constructor
*/
@Test
public void constructor() {

try {
Class<?> stuClass = Class.forName("com.zwang.april.bean.Student");
Constructor<?>[] pubCons = stuClass.getConstructors();
for (Constructor con : pubCons) {
System.out.println(con);
}

System.out.println("**********************所有构造方法*********************************");

Constructor<?>[] allCons = stuClass.getDeclaredConstructors();

for (Constructor con : allCons) {
System.out.println(con);
}

System.out.println("**********************指定构造方法*********************************");

Constructor<?> constructor = stuClass.getDeclaredConstructor(int.class);
System.out.println(constructor);

//不能直接访问非public修饰的构造方法、属性或者方法 否则 Framework Method invoke Explosively
//暴力访问: setAccessible(true)忽略掉访问修饰符
constructor.setAccessible(true);
//Uses the constructor represented by this {@code Constructor} object to
//create and initialize a new instance of the constructor's declaring class
Object instance = constructor.newInstance(1);
System.out.println(instance);

} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
e.printStackTrace();
}
}

/**
* 2.2 访问成员变量并调用
* <p>
* 批量
* class.getFields() 访问所有public修饰的字段
* class.getDeclaredFields() 访问所有字段
* <p>
* 单个
* class.getField(String name) 访问一个指定public修饰的字段
* class.getDeclaredField(String name) 访问所有的字段
* <p>
* 举例:获取某个public修饰的字段 并调用
* (1) Class<?> wClass = Class.forName(); 先获取class对象
* (2) Field f = wClass.getField("name"); 通过getField(String name) 获取public修饰的字段
* (3) Object obj = wClass.getConstructor().newInstance(); 通过构造函数初始化该对象
* (4) f.set(obj,"刘德华"); Field.set(Object obj, Object value); Object ---> 修改字段的对象 value ---> 修改改参数的值(若为private修饰,需要添加访问权限)
* (5) WorkMan man = (WorkMan)obj;
* (6) 打印man
*/
@Test
public void accessField() {
try {
Class<?> workClass = Class.forName("com.zwang.april.bean.WorkMan");

System.out.println("****************访问所有public字段****************");
Field[] pubFields = workClass.getFields();
for (Field f : pubFields) {
System.out.println(f);
}

System.out.println("****************访问所有字段(包括private、protect、默认)****************");
Field[] allFields = workClass.getDeclaredFields();
for (Field f : allFields) {
System.out.println(f);
}


Field name = workClass.getDeclaredField("sex");
System.out.println(name);

//实例化一个对象
Object obj = workClass.getConstructor().newInstance();
//添加字段访问权限
name.setAccessible(true);
//为字段设置值
name.set(obj, '男');
WorkMan workMan = (WorkMan) obj;
System.out.println(workMan);


} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException | InvocationTargetException | InstantiationException | NoSuchMethodException e) {
e.printStackTrace();
}

}

/**
* 2.3 获取成员方法并调用
* 批量
* class.getMethods()
* class.getDeclaredMethods()
* <p>
* 单个
* class.getMethod(String name, Class<?>... parameterTypes) name ---> 方法名 parameterTypes --->方法中的参数
* class.getDeclaredMethod(String name, Class<?>... parameterTypes) name ---> 方法名 parameterTypes --->方法中的参数
* <p>
* <p>
* 调用方法
* ① Class<?> tClass = Class.forName("com.zwang.april.bean.Teacher"); 获取Class对象
* ② Method method = tClass.getDeclaredMethod("show4",int.class); 获取相应的方法
* ③ Object obj = tClass.getConstructor().newInstance(); 通过构造函数进行实例化,生成Class 对象
* ④ method.setAccessible(true); 私有方法需要添加访问权限
* ⑤ Object objectResult = method.invoke(Object obj, Object... args); obj ---> 实例 ,args ---> 传入相应的参数
* 打印
*/
@Test
public void accessMethod() {
try {
Class<?> tClass = Class.forName("com.zwang.april.bean.Teacher");

System.out.println("*****************获取所有public修饰的方法*****************");
Method[] pubMethod = tClass.getMethods();
for (Method m : pubMethod) {
System.out.println(m);
}
System.out.println("*****************获取指定public修饰的方法*****************");
Method show1 = tClass.getMethod("show1", String.class);
System.out.println(show1);

System.out.println("*****************获取所有方法*****************");
Method[] allMethod = tClass.getDeclaredMethods();
for (Method m : allMethod) {
System.out.println(m);
}

System.out.println("*****************获取指定private修饰的方法*****************");
Method show4 = tClass.getDeclaredMethod("show4", int.class);
System.out.println(show4);

//调用
Object obj = tClass.getConstructor().newInstance();
//允许访问
show4.setAccessible(true);
Object result = show4.invoke(obj, 15);
System.out.println(result);


} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
e.printStackTrace();
}

}

/**
* 2.4 反射main方法
* <p>
* ┞ Class<?> mClass = Class.forName("com.zwang.april.bean.StaticMethod"); 获取类名
* ┞ Method mMethod = mClass.getMethod("main", String[].class); 获取main()
* ┞ 因为是静态方法,所以不需要对象调用,可以直接传入null值
* ┞ mMethod.invoke(null,new Object[]{new String[]{"1","2","3"}});
* ┞ 亦或者传入class
* ┞ mMethod.invoke(mClass,new Object[]{new String[]{"1","2","3"}});
*/
@Test
public void accessMain() {
try {
Class<?> mClass = Class.forName("com.zwang.april.bean.StaticMethod");
Method mMethod = mClass.getMethod("main", String[].class);
// mMethod.invoke(null, (Object) new String[]{"1","2","3"});
//因为是静态方法,所以不需要对象调用,此处可以传null或者是mClass(通过类去调用)
// mMethod.invoke(null,new Object[]{new String[]{"1","2","3"}});
mMethod.invoke(mClass, new Object[]{new String[]{"1", "2", "3"}});

} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}

/**
* 3.利用反射 、 越过泛型检查 如下
*/
@Test
public void otherUse() {
ArrayList<String> strList = new ArrayList<>();
strList.add("aaa");
strList.add("bbb");

Class<ArrayList> listClass = ArrayList.class;
try {
Method addMethod = listClass.getMethod("add", Object.class);
addMethod.invoke(strList, 100);

for (Object obj : strList) {
System.out.println(obj);
}
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}

System.out.println("*********************第二种方式***********************");
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
ArrayList mList = list;
mList.add(100);

for (Object obj : mList) {
System.out.println(obj);
}
}


/**
* 深拷贝
* <p>
* 通过实现Serializable接口,并用对象的序列化与反序列化实现真正的深拷贝
*/
public <T extends Serializable> T clone(T obj) {
T cloneObj = null;
try {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream objOut = new ObjectOutputStream(byteOut);
objOut.writeObject(obj);
objOut.close();

ByteArrayInputStream byteInput = new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream objInput = new ObjectInputStream(byteInput);
cloneObj = (T) objInput.readObject();
objInput.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return cloneObj;

}

/**
* 泛型的协变与逆变
* 定义:(≦ 表示继承关系 例如:String extends Object . f(Object) ---> 有Object对象构造出来的一种类型 例如: Object[] 、List)
* 当A ≦ B时,如果有f(A) ≦ f(B),那么f叫做协变;
* 当A ≦ B时,如果有f(B) ≦ f(A),那么f叫做逆变;
* 如果上面两种关系都不成立则叫做不可变。
* <p>
* 现在问题来了:究竟什么时候用extends什么时候用super呢?《Effective Java》给出了答案:
* PECS: producer-extends, consumer-super.
* java.util.Collections的copy方法(JDK1.7)完美地诠释了PECS:
*/
@Test
public void generic() {
Object[] objects = new String[3]; //协变
List<? extends Number> list = new ArrayList<>(); //协变 (extends指定泛型的上边界 super指定泛型的下边界)
List<? super Number> list1 = new ArrayList<>(); //逆变

}

}
# 笔记 # 反射笔记
官网基础
分享
  • 文章目录
  • 站点概览
欢亮

欢亮

天下事有难易乎?为之,则难者亦易矣;不为,则易者亦难矣。
9 日志
6 分类
10 标签
GitHub E-Mail
Links
  • 二松同学
  1. 1. 反射
    1. 1.1. 1. 反射定义:
    2. 1.2. 2. 泛型问题系列:(摘自码农每日一题)
    3. 1.3. 其他
© 2019 欢亮 | 121k | 1:50
由 Hexo 强力驱动 v3.9.0
|
主题 – NexT.Muse v7.3.0