老规矩我们还是先提出几个问题,一门技术必然要能解决一定的问题,才有去学习掌握它的价值
· 一、 什么是反射?
· 二、反射能做什么?
一、 什么是反射?
用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。
如果你是一个Android Developer,前辈们都会教导你尽量少用反射,效率太低,太慢。“射”嘛,射的太快就不好了,所以反射虽然慢点,但是偶尔射一下还是很”爽”的。
二、反射能做什么?
1、新建类的实例
我们知道所有的类都继承子顶级父类Object,而Object中有hashCode()、equals()、clone()、toString()、getClass()等。其中getClass()返回一个Class 对象。我们这里就需要使用的Class对象,注意C是大写,我们可以通过一下方式来获取Class对象
1. Class.forName(“类名字符串”) (注意:类名字符串必须是全称,包名+类名)
2. 类名.class
3. 实例对象.getClass()
在Class类中有一个非常重要的方法
1. public T newInstance() throws InstantiationException, IllegalAccessException {
2. return newInstanceImpl();
3. }
4.
5. private native T newInstanceImpl() throws IllegalAccessException, InstantiationException;
查看Api可以看到调用newInstace方法可以返回当前class对应的实例对象。接下来看一个小的Demo
1. public class Reflection {
2.
3. public static void main(String[] args) {
4.
5. // 普通创建类的实例
6.
7. People p1 = new People();
8. System.out.println(p1.getName());
9. // 利用反射获取类的实例
10. Class clazz = People.class;
11. // 常用方式,注意括号中需要放类的全路径名
12. // Class clazz = Class.forName("reflection.People");
13. // Class clazz = p1.getClass();
14. try {
15. People p2 = (People) clazz.newInstance();
16. System.out.println(p2.getName());
17. } catch (Exception e) {
18. e.printStackTrace();
19. }
20.
21. }
22.
23. }
24.
25. class People {
26.
27. private String name = "张三";
28. private int age;
29.
30. public String getName() {
31. return name;
32. }
33.
34. public void setName(String name) {
35. this.name = name;
36. }
37.
38. public int getAge() {
39. return age;
40. }
41.
42. public void setAge(int age) {
43. this.age = age;
44. }
45.
46. }
输入结果:
1. 张三
2. 张三
2、获取成员变量和方法
在讲之前我们先来看这样一个小按理,JSON数据转JavaBaen对象,在不用解析库的情况下,一般我们会这样做
1. private void analysisDate(JSONObject response) throws JSONException {
2. int announceid = response.getInt("announceid");
3. String title = response.getString("title");
4. String hits = response.getString("hits");
5. String addtime = response.getString("addtime");
6. NewsNotifyItem newsNotifyItem = new NewsNotifyItem(announceid,
7. title, hits, addtime);
8. }
9. }
每当我们需要解析额时候,都需要根据不同javabean来进行相应的解析,我们每次进行的操作都是一样的,只是解析的数据不同而已,结合上篇帖子讲到的泛型,这里我们就可以再利用反射来自己做一个Json解析工具。
下面是我写的一个JsonObject对象转JavaBean的一个工具类,需要注意的是,JSON的key需要和字段名保持一致,先说下思路
①首先通过反射获取JavaBean中的所有字段值的名称
②拼接出set方法
③由于字段名和Json的key值相同,利用自动名获取Json中的值并填充的实例对象中
1. public class Json2BeanUtils {
2.
3. public static <T> T jsonToBean(JSONObject response, Class<T> clazz) {
4. try {
5. // 创建类的实例
6. Object object = Class.forName(clazz.getName()).newInstance();
7. // 获取类中的所有成员变量
8. Field[] fields = object.getClass().getDeclaredFields();
9. for (int i = 0; i < fields.length; i++) {
10. //设置权限
11. fields[i].setAccessible(true);
12. // 获取字段的名称
13. String fieldName = fields[i].getName();
14. // 过滤掉UID
15. if (fieldName.endsWith("serialVersionUID")) {
16. continue;
17. }
18. // 获取字段的类型
19. String fieldType = fields[i].getGenericType().toString();
20. // 拼接出JavaBean中的set方法 这里有一个坑 后面讲解
21. String methodName = "set"
22. + fieldName.substring(0, 1).toUpperCase()
23. + fieldName.substring(1);
24. try {
25. // 判断变量类型
26. if (fieldType.endsWith("class java.lang.String")) {
27. // 获取到set方法
28. Method m = object.getClass().getMethod(methodName,
29. String.class);
30. String value = null;
31. try {
32. // 从JsonObj中取出相应的值
33. value = response.getString(fieldName);
34. } catch (Exception e) {
35. e.printStackTrace();
36. value = "";
37. }
38. if (TextUtils.isEmpty(value)) {
39. value = "";
40. } else if (value.endsWith("null")) {
41. value = "";
42. }
43. // 赋值
44. m.invoke(object, value);
45. } else if (fieldType.endsWith("int")
46. || fieldType.endsWith("class java.lang.Integer")) {
47. // int 类型
48. System.out.println();
49. Method m = object.getClass().getMethod(methodName,
50. int.class);
51. int value = -1;
52. try {
53. value = response.getInt(fieldName);
54. } catch (Exception e) {
55. e.printStackTrace();
56. value = -1;
57. }
58. m.invoke(object, value);
59.
60. } else if (fieldType.endsWith("boolean")
61. || fieldType
62. .endsWith("fieldType:class java.lang.Boolean")) {
63. // boolean 类型
64. Method m = object.getClass().getMethod(methodName,
65. boolean.class);
66. boolean value = false;
67. try {
68. value = response.getBoolean(fieldName);
69. } catch (Exception e) {
70. e.printStackTrace();
71. value = false;
72. }
73. m.invoke(object, value);
74. } else if (fieldType.endsWith("double")
75. || fieldType
76. .endsWith("fieldType:class java.lang.Double")) {
77. // double 类型
78. Method m = object.getClass().getMethod(methodName,
79. double.class);
80. double value = -1D;
81. try {
82. value = response.getDouble(fieldName);
83. } catch (Exception e) {
84. e.printStackTrace();
85. value = -1D;
86. }
87. m.invoke(object, value);
88. } else if (fieldType.endsWith("char")) {
89. // char类型 JSONObject 没有char
90. Method m = object.getClass().getMethod(methodName,
91. String.class);
92. String value = "";
93. try {
94. value = response.getString(fieldName);
95. } catch (Exception e) {
96. e.printStackTrace();
97. value = "";
98. }
99. m.invoke(object, value);
100. } else if (fieldType.endsWith("float")
101. || fieldType
102. .endsWith("fieldType:class java.lang.Float")) {
103. // float类型
104. Method m = object.getClass().getMethod(methodName,
105. double.class);
106. double value = -1D;
107. try {
108. value = response.getDouble(fieldName);
109. } catch (Exception e) {
110. e.printStackTrace();
111. value = -1D;
112. }
113. m.invoke(object, value);
114.
115. } else if (fieldType.endsWith("short")
116. || fieldType
117. .endsWith("fieldType:class java.lang.Short")) {
118. // short
119. Method m = object.getClass().getMethod(methodName,
120. short.class);
121. int value = -1;
122. try {
123. value = response.getInt(fieldName);
124. } catch (Exception e) {
125. e.printStackTrace();
126. value = -1;
127. }
128. m.invoke(object, value);
129. } else if (fieldType.endsWith("byte")
130. || fieldType
131. .endsWith("fieldType:class java.lang.Byte")) {
132. Method m = object.getClass().getMethod(methodName,
133. byte.class);
134. int value = -1;
135. try {
136. value = response.getInt(fieldName);
137. } catch (Exception e) {
138. e.printStackTrace();
139. value = -1;
140. }
141. m.invoke(object, value);
142. } else if (fieldType.endsWith("long")
143. || fieldType
144. .endsWith("fieldType:class java.lang.Long")) {
145. Method m = object.getClass().getMethod(methodName,
146. long.class);
147. Long value = -1L;
148. try {
149. value = response.getLong(fieldName);
150. } catch (Exception e) {
151. e.printStackTrace();
152. value = -1L;
153. }
154. m.invoke(object, value);
155. }
156. } catch (Exception e) {
157. // TODO: handle exception
158. }
159. }
160. return (T) object;
161. } catch (Exception e) {
162. e.printStackTrace();
163. }
164.
165. return null;
166. }
167.
168. }
这里需要注意一个坑,先来看一段代码
1. class People {
2.
3. private String name;
4. private int age;
5. private String mSex;
6.
7. public String getName() {
8. return name;
9. }
10.
11. public void setName(String name) {
12. this.name = name;
13. }
14.
15. public int getAge() {
16. return age;
17. }
18.
19. public void setAge(int age) {
20. this.age = age;
21. }
22.
23. public String getmSex() {
24. return mSex;
25. }
26. // 这里就出了问题
27. public void setmSex(String mSex) {
28. this.mSex = mSex;
29. }
30.
31. }
当我们自动生成get set方法时,会将字段的首字母大写,我们在上面拼接set 方法时,也是基于这样的规则来拼装的。但是 当我们的字段名为 aAbbb 时,则生成的get set 方法则不会大写。解决方案也很简单,注意字段命名或者在拼接时对第二个自动进行大小写判断。这样我们自己写的Json解析工具就搞定, 以后每次解析只需一行代码即可OK。
登录 | 立即注册