Java反射最佳实践

   2016-10-31 0
核心提示:学习Java的同学注意了!!!学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:279558494我们一起学Java!概要:最简单优雅的使用反射。一、需求今天一个“懒”程序员突然跑过来说:“反射好麻烦,我要提点需求。”听到这句话

学习Java的同学注意了!!!学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码: 279558494 我们一起学Java!

概要:最简单优雅的使用反射。

一、需求

今天一个“懒”程序员突然跑过来说:“反射好麻烦,我要提点需求。”

听到这句话后我就知道,今天一定不好过了,奇葩需求又来了。

我们之前写反射都是要这么写:

public static <T> T create(HttpRequest httpRequest) {
        Object httpRequestEntity = null;
        try {
            Class<T> httpRequestEntityCls = (Class<T>) Class.forName(HttpProcessor.PACKAGE_NAME + "." + HttpProcessor.CLASS_NAME);
            Constructor con = httpRequestEntityCls.getConstructor(HttpRequest.class);
            httpRequestEntity = con.newInstance(httpRequest);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return (T) httpRequestEntity;
    }

因为反射在开发中很少用(做普通的业务开发的话),仅仅在自己写一些框架和注解框架时会用到,所以对api总是不熟悉。每次用到api都要去网上查,查了后又得自己实验下,很不爽。更差劲的是这样写法可读性十分低下。我不希望这样写反射,我希望反射能像

String str = new String();

这样简单,一行代码搞定!。

此外,有很多人都说反射影响性能,在开发的时候要避免用反射。那么什么时候该用反射,什么时候不用反射呢?用什么方式来避免反射呢?如果不明白什么时候用反射,就很难将反射活学活用了。

二、分析

当我们接到上面需求后,我长舒一口气,因为这回的需求还比较简单。

我相信有人会说:“反射就那几个api,一直没变过,你就不会自己去查啊,觉得麻烦就别写代码啊,不知道反射的内部细节你怎么去提高呢?”

其实不然,重复写麻烦的代码和提高自己的代码能力是完全无关的,我实在不知道我们写了成千上万行的findViewById后除了知道类要和xml文件绑定外,还学到了什么。

那么这回我们继续来挑战传统思维和模板式代码,来看看新一代的反射代码应该怎么写,如何用一行代码来反射出类。

在做之前,来看看我们一般用反射来干嘛?

1.反射构建出无法直接访问的类

2.set或get到无法访问的类变量

3.调用不可访问的方法

三、解决方案

3.1 一行代码写反射

作为一个Android程序员,索性就拿TextView这个类开刀吧。首先定义一个类变量:

TextView mTv;

通过反射得到实例:

// 有参数,建立类
mTv = Reflect.on(TextView.class).create(this).get();

// 通过类全名得到类
String word = Reflect.on("java.lang.String").create("Reflect TextView").get();

// 无参数,建立类
Fragment fragment = Reflect.on(Fragment.class).create().get();

通过反射调用方法:

// 调用无参数方法
L.d("call getText() : " + Reflect.on(mTv).call("getText").toString());

// 调用有参数方法
Reflect.on(mTv).call("setTextColor", 0xffff0000);

通过反射get、set类变量

TextView中有个mText变量,来看看我们怎么接近它。

// 设置参数
Reflect.on(mTv).set("mText", "---------- new Reflect TextView ----------");

// 获得参数
L.d("setgetParam is " + Reflect.on(mTv).get("mText"));

3.2 什么时候该用反射,什么时候不用反射

又到了这样权衡利弊的时候了,首先我们明确,在日常开发中尽量不要用反射,除非遇到了必须要通过反射才能调用的方法。比如我在做一个下拉通知中心功能的时候就遇到了这样的情况。系统没有提供api,所以我们只能通过反射进行调用,所以我自己写了这样一段代码:

<uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/>
private static void doInStatusBar(Context mContext, String methodName) {
        try {
            Object service = mContext.getSystemService("statusbar");
            Method expand = service.getClass().getMethod(methodName);
            expand.invoke(service);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 显示消息中心
     */
    public static void openStatusBar(Context mContext) {
        // 判断系统版本号
        String methodName = (VERSION.SDK_INT <= 16) ? "expand" : "expandNotificationsPanel";
        doInStatusBar(mContext, methodName);
    }

    /**
     * 关闭消息中心
     */
    public static void closeStatusBar(Context mContext) {
        // 判断系统版本号
        String methodName = (VERSION.SDK_INT <= 16) ? "collapse" : "collapsePanels";
        doInStatusBar(mContext, methodName);
    }

先来看看利用jOOR写的doInStatusBar方法会简洁到什么程度:

private static void doInStatusBar(Context mContext, String methodName) {
        Object service = mContext.getSystemService("statusbar");
        Reflect.on(service).call(methodName);
    }

哇,就一行代码啊,很爽吧~

爽完了,我们就来看看反射问题吧。因为不是系统给出的api,所以谷歌在不同的版本上用了不同的方法名来做处理,用反射的话我们就必须进行版本的判断,这是需要注意的,此外反射在性能方面确实不好,这里需要谨慎。

我的建议:

如果一个类中有很多地方都是private的,而你的需求都需要依赖这些方法或者变量,那么比起用反射,推荐把这个类复制出来,变成自己的类,像是toolbar这样的类就可以进行这样的操作。

在自己写框架的时候,我们肯定会用到反射,很简单的例子就是事件总线和注解框架,翔哥就说过一句话:无反射,无框架。也正因为是自己写的框架,所以通过反射调用的方法名和参数一般不会变,更何况做运行时注解框架的话,反射肯定会出现。在这种情况下千万不要害怕反射,索性放心大胆的做。因为它会让你完成很多不可能完成的任务。

总结下来就是:

实际进行日常开发的时候尽量少用反射,可以通过复制原始类的形式来避免反射。在写框架时,不避讳反射,在关键时利用反射来助自己一臂之力。

四、后记

我们终于完成了用一行代码写反射,避免了很多无意义的模板式代码。需要再次说明的是,本文是依据jOOR 进行编写的,这里有原项目readme的中文翻译。

jOOR是我无意中遇到的开源库,第一次见到它时我就知道这个是我想要的,因为那时候我被反射搞的很乱,而它简洁的编码方式给我带来了新的思考,大大提高了代码可读性。顺便一说,作者人比较好(就是死活不愿意让我放入中文的readme),技术也很不错。该项目有很详细的测试用例,并且还给出了几个类似的反射调用封装库。可见作者在写库时做了大量的调研和测试工作,让我们可以放心的运用该库(其实就两个类)。

本文希望带给大家一个反射的新思路,给出一个最简单实用的反射写法,希望能被大家迅速运用到实践中去。更加重要的是,通过对jOOR的分析,让我知道了写库前应该调研类似的库,而不是完全的创造新轮子,调研和测试是代码稳定性的重要保障。

学习Java的同学注意了!!!学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码: 279558494 我们一起学Java!

 
标签: Java 安卓开发
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • SDK热更之如何在SDK代码中自动插桩及如何生成补
    写在前面本文是SDKHotfix相关的SDK热更系列文章中的一篇,以下为项目及系列文章相关链接:SDKHotfix整体介绍:http://blog.bihe0832.com/sdk_hotfix_project.htmlSDKHotfix对应github地址:https://github.com/bihe0832/SDKHoxFix这篇文章主要介绍一下SDK热更
  • ASimpleCache
    ASimpleCache 是一个为android制定的 轻量级的 开源缓存框架。轻量到只有一个java文件(由十几个类精简而来)。1、它可以缓存什么东西?普通的字符串、JsonObject、JsonArray、Bitmap、Drawable、序列化的java对象,和 byte数据。2、它有什么特色?特色主要是
    02-05 Java开源
  • 原生App与javascript交互之JSBridge接口原理、
    前期调研调研对象:支付宝,微信,云之家调研文档:Android中JS与Java的极简交互库 SimpleJavaJsBridge设计需求阅读类型的业务功能页面需要由前端H5实现,需要做到服务端可控;页面界面更改减少重新发布新版本的频率;功能页面部分原型需求无法实现,需要原生
  • RxJava系列番外篇:一个RxJava解决复杂业务逻辑
    之前写过一系列RxJava1的文章,也承诺过会尽快有RxJava2的介绍。无奈实际项目中还未真正的使用RxJava2,不敢妄动笔墨。所以这次还是给大家分享一个使用RxJava1解决问题的案例,希望对大家在使用RxJava的时候有一点点启发。对RxJava还不了解的同学可以先去看看
  • 框架Robust原理解析(下)
    框架Robust原理解析(下)
    一、回顾框架原理本篇继续来看热修复框架Robust原理,在之前的一篇文章中已经详细讲解了:Robust框架原理,因为这个框架不是开源的,所以通过官方给出的原理介绍,咋们自己模拟了案例和框架逻辑的简单实践。最后在通过反编译美团app进行验证咋们的逻辑实现是
  • 使用Smalidea对无源码APK调试简介
    阅读:8最近正好也用了Smalidea,就ZZ的原贴做一些补充。可调试APP如果Android的系统属性ro.debuggable等于1(用getprop ro.debuggable验证),则所有APP都可调试。如果ro.debuggable等于0,某APP的AndroidManifest.xml中有android:debuggable=”true”,该APP
    01-06 JavaLinux
  • 年度盘点(四) | 2016 年十大 Java / Android 开发者必读好文
    年度盘点(四) | 2016 年十大 Java / Android
    2016 年已经过去,感谢大家支持开发者头条。 年度盘点第四篇: 2016 年十大 Java / Android 开发者必读好文 。 长按识别文章摘要下方二维码,即可进入文章评论页。0. 推荐几个自己写的 Java 后端相关的范例项目这里推荐几个自己写的范例项目,主要采用 SSM(S
  • 8个华丽而实用的Java图表类库
    8个华丽而实用的Java图表类库
    学习Java的同学注意了!!! 学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码: 589809992 我们一起学Java! 前段时间我们为大家分享过一些最常用的Java图表应用和Android图表应用,无论是在PC平台上还是移动平台上,图表和报
  • 第151期:一个RxJava解决复杂业务逻辑的案例
    第151期:一个RxJava解决复杂业务逻辑的案例
    第151期:一个RxJava解决复杂业务逻辑的案例深度讨论 基本特效:饿了么丝滑无缝过度搜索栏的实现 diycode 帖子优先,就给上个头条吧。Android开发 一个RxJava解决复杂业务逻辑的案例 本文给大家分享一个使用RxJava解决问题的案例,希望对大家在使用RxJava的时
  • Eclipse 集成ijkplayer demo
    Eclipse 集成ijkplayer demo
    接着上一篇在Mac上编译ijkplayer的.so,现在将这些文件夹拷贝到windows上。(在mac和winds上集成到eclipse上是一样的,只是我这mac上没有安装eclipse)。现在开始说集成到Eclipse的步骤:1 更改目录结构 以 ijkplayer-armv7a 文件夹为例,删除选中的这四个文件
    12-23 EclipseJava
点击排行