在路上

 找回密码
 立即注册
在路上 站点首页 学习 查看内容

Java高级特性之反射

2017-2-7 13:40| 发布者: zhangjf| 查看: 507| 评论: 0

摘要: 老规矩我们还是先提出几个问题,一门技术必然要能解决一定的问题,才有去学习掌握它的价值 一、 什么是反射? 二、反射能做什么? 一、 什么是反射? 用在Java身上指的是我们可以于运行时加载、探知、使用编译期 ...

老规矩我们还是先提出几个问题,一门技术必然要能解决一定的问题,才有去学习掌握它的价值

一、 什么是反射? 二、反射能做什么?
一、 什么是反射?
用在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. private native T newInstanceImpl() throws IllegalAccessException, InstantiationException;
复制代码

查看Api可以看到调用newInstace方法可以返回当前class对应的实例对象。接下来看一个小的Demo

  1. public class Reflection {
  2. public static void main(String[] args) {
  3. // 普通创建类的实例
  4. People p1 = new People();
  5. System.out.println(p1.getName());
  6. // 利用反射获取类的实例
  7. Class clazz = People.class;
  8. // 常用方式,注意括号中需要放类的全路径名
  9. // Class clazz = Class.forName("reflection.People");
  10. // Class clazz = p1.getClass();
  11. try {
  12. People p2 = (People) clazz.newInstance();
  13. System.out.println(p2.getName());
  14. } catch (Exception e) {
  15. e.printStackTrace();
  16. }
  17. }
  18. }
  19. class People {
  20. private String name = "张三";
  21. private int age;
  22. public String getName() {
  23. return name;
  24. }
  25. public void setName(String name) {
  26. this.name = name;
  27. }
  28. public int getAge() {
  29. return age;
  30. }
  31. public void setAge(int age) {
  32. this.age = age;
  33. }
  34. }
复制代码

输入结果:
张三
张三
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. public static <T> T jsonToBean(JSONObject response, Class<T> clazz) {
  3. try {
  4. // 创建类的实例
  5. Object object = Class.forName(clazz.getName()).newInstance();
  6. // 获取类中的所有成员变量
  7. Field[] fields = object.getClass().getDeclaredFields();
  8. for (int i = 0; i < fields.length; i++) {
  9. //设置权限
  10. fields[i].setAccessible(true);
  11. // 获取字段的名称
  12. String fieldName = fields[i].getName();
  13. // 过滤掉UID
  14. if (fieldName.endsWith("serialVersionUID")) {
  15. continue;
  16. }
  17. // 获取字段的类型
  18. String fieldType = fields[i].getGenericType().toString();
  19. // 拼接出JavaBean中的set方法 这里有一个坑 后面讲解
  20. String methodName = "set"
  21. + fieldName.substring(0, 1).toUpperCase()
  22. + fieldName.substring(1);
  23. try {
  24. // 判断变量类型
  25. if (fieldType.endsWith("class java.lang.String")) {
  26. // 获取到set方法
  27. Method m = object.getClass().getMethod(methodName,
  28. String.class);
  29. String value = null;
  30. try {
  31. // 从JsonObj中取出相应的值
  32. value = response.getString(fieldName);
  33. } catch (Exception e) {
  34. e.printStackTrace();
  35. value = "";
  36. }
  37. if (TextUtils.isEmpty(value)) {
  38. value = "";
  39. } else if (value.endsWith("null")) {
  40. value = "";
  41. }
  42. // 赋值
  43. m.invoke(object, value);
  44. } else if (fieldType.endsWith("int")
  45. || fieldType.endsWith("class java.lang.Integer")) {
  46. // int 类型
  47. System.out.println();
  48. Method m = object.getClass().getMethod(methodName,
  49. int.class);
  50. int value = -1;
  51. try {
  52. value = response.getInt(fieldName);
  53. } catch (Exception e) {
  54. e.printStackTrace();
  55. value = -1;
  56. }
  57. m.invoke(object, value);
  58. } else if (fieldType.endsWith("boolean")
  59. || fieldType
  60. .endsWith("fieldType:class java.lang.Boolean")) {
  61. // boolean 类型
  62. Method m = object.getClass().getMethod(methodName,
  63. boolean.class);
  64. boolean value = false;
  65. try {
  66. value = response.getBoolean(fieldName);
  67. } catch (Exception e) {
  68. e.printStackTrace();
  69. value = false;
  70. }
  71. m.invoke(object, value);
  72. } else if (fieldType.endsWith("double")
  73. || fieldType
  74. .endsWith("fieldType:class java.lang.Double")) {
  75. // double 类型
  76. Method m = object.getClass().getMethod(methodName,
  77. double.class);
  78. double value = -1D;
  79. try {
  80. value = response.getDouble(fieldName);
  81. } catch (Exception e) {
  82. e.printStackTrace();
  83. value = -1D;
  84. }
  85. m.invoke(object, value);
  86. } else if (fieldType.endsWith("char")) {
  87. // char类型 JSONObject 没有char
  88. Method m = object.getClass().getMethod(methodName,
  89. String.class);
  90. String value = "";
  91. try {
  92. value = response.getString(fieldName);
  93. } catch (Exception e) {
  94. e.printStackTrace();
  95. value = "";
  96. }
  97. m.invoke(object, value);
  98. } else if (fieldType.endsWith("float")
  99. || fieldType
  100. .endsWith("fieldType:class java.lang.Float")) {
  101. // float类型
  102. Method m = object.getClass().getMethod(methodName,
  103. double.class);
  104. double value = -1D;
  105. try {
  106. value = response.getDouble(fieldName);
  107. } catch (Exception e) {
  108. e.printStackTrace();
  109. value = -1D;
  110. }
  111. m.invoke(object, value);
  112. } else if (fieldType.endsWith("short")
  113. || fieldType
  114. .endsWith("fieldType:class java.lang.Short")) {
  115. // short
  116. Method m = object.getClass().getMethod(methodName,
  117. short.class);
  118. int value = -1;
  119. try {
  120. value = response.getInt(fieldName);
  121. } catch (Exception e) {
  122. e.printStackTrace();
  123. value = -1;
  124. }
  125. m.invoke(object, value);
  126. } else if (fieldType.endsWith("byte")
  127. || fieldType
  128. .endsWith("fieldType:class java.lang.Byte")) {
  129. Method m = object.getClass().getMethod(methodName,
  130. byte.class);
  131. int value = -1;
  132. try {
  133. value = response.getInt(fieldName);
  134. } catch (Exception e) {
  135. e.printStackTrace();
  136. value = -1;
  137. }
  138. m.invoke(object, value);
  139. } else if (fieldType.endsWith("long")
  140. || fieldType
  141. .endsWith("fieldType:class java.lang.Long")) {
  142. Method m = object.getClass().getMethod(methodName,
  143. long.class);
  144. Long value = -1L;
  145. try {
  146. value = response.getLong(fieldName);
  147. } catch (Exception e) {
  148. e.printStackTrace();
  149. value = -1L;
  150. }
  151. m.invoke(object, value);
  152. }
  153. } catch (Exception e) {
  154. // TODO: handle exception
  155. }
  156. }
  157. return (T) object;
  158. } catch (Exception e) {
  159. e.printStackTrace();
  160. }
  161. return null;
  162. }
  163. }
复制代码

这里需要注意一个坑,先来看一段代码

  1. class People {
  2. private String name;
  3. private int age;
  4. private String mSex;
  5. public String getName() {
  6. return name;
  7. }
  8. public void setName(String name) {
  9. this.name = name;
  10. }
  11. public int getAge() {
  12. return age;
  13. }
  14. public void setAge(int age) {
  15. this.age = age;
  16. }
  17. public String getmSex() {
  18. return mSex;
  19. }
  20. // 这里就出了问题
  21. public void setmSex(String mSex) {
  22. this.mSex = mSex;
  23. }
  24. }
复制代码

当我们自动生成get set方法时,会将字段的首字母大写,我们在上面拼接set 方法时,也是基于这样的规则来拼装的。但是 当我们的字段名为 aAbbb 时,则生成的get set 方法则不会大写。解决方案也很简单,注意字段命名或者在拼接时对第二个自动进行大小写判断。这样我们自己写的Json解析工具就搞定, 以后每次解析只需一行代码即可OK。
今天反射就暂时讲到这里。其实反射的作用远不于此,这里只是使用了反射的冰山一角,结合注解和泛型,反射可以做的事更多,但是还是和开头讲的一样,反射用起来虽然很爽,但是不能乱射,和频繁的射,“射”的太多。“性”能会出问题!(o(∩_∩)o )。

来自: http://blog.csdn.net/soul_code/article/details/50466935

上一篇:Java高级特性之泛型下一篇:jstack命令

最新评论

小黑屋|在路上 ( 蜀ICP备15035742号-1 

;

GMT+8, 2025-7-9 03:13

Copyright 2015-2025 djqfx

返回顶部