Foreword

反射的作用我在这就不多说了,每次用到反射都是那么一坨代码丢进去,总是让人觉得很不优雅,如今有了我这个反射工具类,那么大家就可以一句话优雅地来完成反射的工作,该工具类是站在 jOOR 的肩膀上进行改造,修复了它没有完成的工作,至于修复了什么,后面源码分析会详述,至于这个工具类在哪,现已加入至 1.12.0 版本的 AndroidUtilCode,下面来介绍下其功能。

Functions

其 APIs 如下所示:

反射相关 -> ReflectUtils.java -> Test

reflect    : 设置要反射的类
newInstance: 实例化反射对象
field      : 设置反射的字段
method     : 设置反射的方法
get        : 获取反射想要获取的
复制代码

Use

实例化反射对象

比如,我们实例化一个 String 对象可以这样做:

String str1 = ReflectUtils.reflect(String.class).newInstance().get();
// equals: String str1 = new String();String str2 = ReflectUtils.reflect("java.lang.String").newInstance("abc").get();
// equals: String str2 = new String("abc");String str3 = ReflectUtils.reflect(String.class).newInstance("abc".getBytes()).get();
// equals: String str3 = new String("abc".getBytes());
复制代码

设置反射的方法

比如,我们想要调用 Stringsubstring 函数可以这样做:

String str1 = ReflectUtils.reflect((Object) "1234").method("substring", 2).get();
// equals: String str1 = "1234".substring(2);String str2 = ReflectUtils.reflect((Object) "1234").method("substring", 0, 2).get();
// equals: String str1 = "1234".substring(0, 2);
复制代码

设置反射的字段

比如,TestPrivateStaticFinal.java 如下所示:

public class TestPrivateStaticFinal {private static final int     I1 = new Integer(1);private static final Integer I2 = new Integer(1);
}
复制代码

我们要设置其 I1I2 值为 2,可以如下操作:

ReflectUtils.reflect(TestPrivateStaticFinal.class).field("I1", 2);
ReflectUtils.reflect(TestPrivateStaticFinal.class).field("I2", 2);
复制代码

要获取其 I1I2 值的话,可以如下操作:

ReflectUtils.reflect(TestPrivateStaticFinal.class).field("I1").get()
ReflectUtils.reflect(TestPrivateStaticFinal.class).field("I2").get()
复制代码

当然,字段操作也有更高级的操作,比如 Test1.java 测试类如下所示:

public class Test1 {public static int     S_INT1;public static Integer S_INT2;public        int     I_INT1;public        Integer I_INT2;public static Test1 S_DATA;public        Test1 I_DATA;
}
复制代码

我对其进行的单元测试如下所示:

@Test
public void fieldAdvanced() throws Exception {ReflectUtils.reflect(Test1.class).field("S_DATA", ReflectUtils.reflect(Test1.class).newInstance())// 设置 Test1.class 中 S_DATA 字段 为 new Test1().field("S_DATA")// 获取到 Test1.class 中 S_DATA 字段.field("I_DATA", ReflectUtils.reflect(Test1.class).newInstance())// 获取到 Test1.class 中 S_DATA 字段 的 I_DATA 为 new Test1().field("I_DATA")// 获取到 Test1.class 中 S_DATA 字段 的 I_DATA 字段.field("I_INT1", 1)// 设置 Test1.class 中 S_DATA 字段 的 I_DATA 字段的 I_INT1 值为 1.field("S_INT1", 2);// 设置 Test1.class 中 S_DATA 字段 的 S_INT1 字段的 I_INT1 值为 2assertEquals(2, Test1.S_INT1);// 静态变量就是最后设置的 2assertEquals(null, Test1.S_INT2);// 没操作过就是 nullassertEquals(0, Test1.S_DATA.I_INT1);// 没操作过就是 0assertEquals(null, Test1.S_DATA.I_INT2);// 没操作过就是 0assertEquals(1, Test1.S_DATA.I_DATA.I_INT1);// 倒数第二步操作设置为 1assertEquals(null, Test1.S_DATA.I_DATA.I_INT2);// 没操作过就是 null
}
复制代码

根据如上注释相信大家也可以理解一二了,如果还想了解更多使用方式,可以查看我写的单元测试类 ReflectUtilsTest,其使用方式就介绍到这里,下面介绍其实现方式。

Achieve

实现的话是站在 jOOR 的肩膀上进行改造,其内部封装了一个 private final Object object; 变量,每次进行反射操作时都会重新实例化一个变量并把结果赋予该变量,最终 get() 就是获取其值,比如我们来看一下 newInstance 的操作,其涉及的代码如下所示:

/*** 实例化反射对象** @param args 实例化需要的参数* @return {@link ReflectUtils}*/
public ReflectUtils newInstance(Object... args) {Class<?>[] types = getArgsType(args);try {Constructor<?> constructor = type().getDeclaredConstructor(types);return newInstance(constructor, args);} catch (NoSuchMethodException e) {List<Constructor<?>> list = new ArrayList<>();for (Constructor<?> constructor : type().getDeclaredConstructors()) {if (match(constructor.getParameterTypes(), types)) {list.add(constructor);}}if (list.isEmpty()) {throw new ReflectException(e);} else {sortConstructors(list);return newInstance(list.get(0), args);}}
}private Class<?>[] getArgsType(final Object... args) {if (args == null) return new Class[0];Class<?>[] result = new Class[args.length];for (int i = 0; i < args.length; i++) {Object value = args[i];result[i] = value == null ? NULL.class : value.getClass();}return result;
}private void sortConstructors(List<Constructor<?>> list) {Collections.sort(list, new Comparator<Constructor<?>>() {@Overridepublic int compare(Constructor<?> o1, Constructor<?> o2) {Class<?>[] types1 = o1.getParameterTypes();Class<?>[] types2 = o2.getParameterTypes();int len = types1.length;for (int i = 0; i < len; i++) {if (!types1[i].equals(types2[i])) {if (wrapper(types1[i]).isAssignableFrom(wrapper(types2[i]))) {return 1;} else {return -1;}}}return 0;}});
}private ReflectUtils newInstance(final Constructor<?> constructor, final Object... args) {try {return new ReflectUtils(constructor.getDeclaringClass(),accessible(constructor).newInstance(args));} catch (Exception e) {throw new ReflectException(e);}
}private final Class<?> type;private final Object object;private ReflectUtils(final Class<?> type, Object object) {this.type = type;this.object = object;
}
复制代码

jOOR 所没有做到的就是没有对多个符合的 Constructor 进行排序,而是直接返回了第一个与之匹配的。这样说有点抽象,我举个例子应该就明白了,比如说有两个构造函数如下所示:

public class Test {public Test(Number n) {}public Test(Object n) {}
}
复制代码

jOOR 反射调用构造函数参数传入 Long 类型,很可能就会走 Test(Object n) 这个构造函数,而我修改过后就是对多个符合的 Constructor 进行排序,匹配出与之最接近的父类,也就是会走 Test(Number n) 这个构造函数,同理,在后面的 method 中的参数匹配 jOOR 也是存在这个问题,我也已经对其修复了。

还有就是 jOOR 对 private static final 字段先 getset 会报异常 java.lang.IllegalAccessException 异常,是因为对 private static final 字段 get 的时候没有去除 final 属性,如果在 get 时就把 final 去掉即可解决,那样在 set 的时候就不会报错。然而,在 Android 的 SDK 中是没有 Field.class.getDeclaredField("modifiers") 这个字段的,所以会报 NoSuchFieldException 异常,这方面我做了容错处理,相关代码如下所示:

/*** 设置反射的字段** @param name 字段名* @return {@link ReflectUtils}*/
public ReflectUtils field(final String name) {try {Field field = getField(name);return new ReflectUtils(field.getType(), field.get(object));} catch (IllegalAccessException e) {throw new ReflectException(e);}
}/*** 设置反射的字段** @param name  字段名* @param value 字段值* @return {@link ReflectUtils}*/
public ReflectUtils field(String name, Object value) {try {Field field = getField(name);field.set(object, unwrap(value));return this;} catch (Exception e) {throw new ReflectException(e);}
}private Field getField(String name) throws IllegalAccessException {Field field = getAccessibleField(name);if ((field.getModifiers() & Modifier.FINAL) == Modifier.FINAL) {try {Field modifiersField = Field.class.getDeclaredField("modifiers");modifiersField.setAccessible(true);modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);} catch (NoSuchFieldException ignore) {// runs in android will happen}}return field;
}private Field getAccessibleField(String name) {Class<?> type = type();try {return accessible(type.getField(name));} catch (NoSuchFieldException e) {do {try {return accessible(type.getDeclaredField(name));} catch (NoSuchFieldException ignore) {}type = type.getSuperclass();} while (type != null);throw new ReflectException(e);}
}private Object unwrap(Object object) {if (object instanceof ReflectUtils) {return ((ReflectUtils) object).get();}return object;
}
复制代码

所以该工具类既完美支持 Java,也完美支持 Android。

Conclusion

好了,这次反射工具类就介绍到这了,是不是觉得如斯优雅,如果觉得好的话以后遇到反射的问题,那就快用我这个工具类吧,这么好的东西藏着不用真的是可惜了哦。

关于安卓核心常用工具类我已经差不多都封装了,今后应该也不会在核心的里面新增了,除非确实很需要我才会再新增某个工具类,其余不常用的我都会放在 subutil 中,感谢大家一直陪伴着 AndroidUtilCode 的成长。

反射工具类,如斯优雅相关推荐

  1. 反射工具类 java_Java反射工具类

    importjava.lang.reflect.Field;importjava.lang.reflect.Method;/*** Java反射工具类 * 提供以下几个功能: * 1. 取最简类名 * ...

  2. 【Android 插件化】Hook 插件化框架 ( 反射工具类 | 反射常用操作整理 )

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  3. 反射工具类ReflectionUtils

    为什么80%的码农都做不了架构师?>>>    package net.pm.common.toolkit;import java.lang.reflect.Field; impor ...

  4. 【java reflection】反射工具类总结

    这段时间公司搞封闭开发,做一个联通总部的客服系统项目,是基于springboot的.在开发工程中遇到一个页面datagrid数据排序的功能,因为有多个表的数据都要用到排序功能,于是我就写了一个排序功能 ...

  5. 反射工具类Reflections

    import java.lang.reflect.*;/*** 反射工具类.* * 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实 ...

  6. java根据属性获取对象_java反射工具类--通过指定属性名,获取/设置对象属性值

    java对象通过点运算符操作对象属性的方式没法使用for,while等循环,此工具主要解决这一问题. 例如:有一对象包含属性有一定规律 obj1: { name1: "张三", a ...

  7. java 反射 接口工具类_Java 反射工具类 ReflectionUtils

    import lombok.extern.slf4j.Slf4j; import java.lang.reflect.*; /** * 反射的 Utils 函数集合 * 提供访问私有变量, 获取泛型类 ...

  8. java反射怎么获取结构体_java反射-使用反射获取类的所有信息

    在OOP(面向对象)语言中,最重要的一个概念就是:万事万物皆对象. 在java中,类也是一个对象,是java.lang.Class的实例对象,官网称该对象为类的类类型. Class 类的实例表示正在运 ...

  9. commons-lang3-3.2.jar中的常用工具类的使用

    这个包中的很多工具类可以简化我们的操作,在这里简单的研究其中的几个工具类的使用. 1.StringUtils工具类 可以判断是否是空串,是否为null,默认值设置等操作: /*** StringUti ...

最新文章

  1. oss图片数据转图片二进制数据_图片数据不够快来试试这些数据增强
  2. ASP.NET Core 6.0对热重载的支持
  3. 去掉字符串后面所有的0 去掉字符串前面或后面的0;
  4. Qt文档阅读笔记-Multiple Inheritance Example 实例解析及Automatic Connections解析
  5. Python subprocess.check_output 执行shell命令 返回结果(单次执行shell命令)
  6. 【接口测试】接口和接口文档概念
  7. 程序设计中的一些感悟
  8. 拓端tecdat|R语言空气污染数据的地理空间可视化和分析:颗粒物2.5(PM2.5)和空气质量指数(AQI)
  9. 数据分析之matplotlib和numpy的应用
  10. html购物车结算代码,JavaScript购物车结算案例
  11. 如何删除在System中打开的iso文件
  12. 字节跳动大数据研发面试——自我反省
  13. OpenStack之Magnum容器编服务排引擎详解
  14. python、turtle实现泊松盘采样
  15. 【QQ for Linux】centos7 下安装qq
  16. latex中如何处理下划线和百分号
  17. 一文带你Linux系统编程入门
  18. 通证经济将在两个方向上闯出新路——元道、孟岩对话
  19. linux yum安装时找不到mirror
  20. Dell笔记本设置为从光驱启动

热门文章

  1. 2d与2.5d坐标转换_Three.js 地理坐标和三维空间坐标的转换
  2. 2016计算机有哪些专业知识点,2016计算机专业知识:精选知识点练习(99)
  3. python红色_python把红玫瑰变成蓝色女巫,将,红色,转化,为,蓝色妖姬
  4. __getitem__的作用
  5. ajax连接云数据库密码,ajax和数据库连接
  6. 用Python发送邮件
  7. spring扫描自定义注解并进行操作
  8. Modbus名词解释
  9. Jquery获取select标签的值、文本方式
  10. Fabricjs在Canvas上使用路径Path绘制不规则图形