关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » JAVA »Java 反射最佳实践

    Java 反射最佳实践

    2015-09-23 00:00:00 出处:潘家邦
    分享

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

    ITJS的这篇文章的例子都可以在示例代码中看到并下载,如果喜欢请star,如果觉得有纰漏请提交issue,如果你有更好的点子可以提交pull request。ITJS的这篇文章的示例代码主要是基于jOOR行编写的,如果想了解更多请查看这里的测试代码。

    一、需求

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

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

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

    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这样的类就可以进行这样的操作。

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

    总结下来就是:

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

    四、后记

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

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

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

    参考自

    http://www.cnblogs.com/tianzhijiexian/p/3906774.html
    https://github.com/tianzhijiexian/HttpAnnotation/blob/master/lib/src/main/java/kale/net/http/util/HttpReqAdapter.java

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    帝国CMS7.5编辑器上传图片取消宽高的三种方法

    帝国cms如何自动生成缩略图的实现方法

    Windows 12即将到来,将彻底改变人机交互

    帝国CMS 7.5忘记登陆账号密码怎么办?可以phpmyadmin中重置管理员密码

    帝国CMS 7.5 后台编辑器换行,修改回车键br换行为p标签

    Windows 11 版本与 Windows 10比较,新功能一览

    Windows 11激活产品密钥收集及专业版激活方法

    如何从 Windows 11 中完全删除/卸载 OneNote?无解!

    抖音安全与信任开放日:揭秘推荐算法,告别单一标签依赖

    ultraedit编辑器打开文件时,总是提示是否转换为DOS格式,如何关闭?

    IT头条

    华为Pura80系列新机预热,余承东力赞其复杂光线下的视频拍摄实力

    01:28

    阿里千问3开源首战告捷:全球下载破千万,国产AI模型崛起新高度!

    01:22

    DeepSeek R1小版本试升级:网友实测编程能力已达到国际一线水平

    23:15

    NVIDIA 与 Dell 合作,大规模交付 Blackwell AI 系统

    20:52

    Cerebras 以最快的 Llama 4 Maverick 性能引领 LLM 推理竞赛

    20:51

    技术热点

    PHP中的随机性——你觉得自己幸运吗?

    搞定Ubuntu Linux下WPA无线上网

    Java使用内存映射实现大文件的上传

    MySQL安全性指南

    MySQL两项性能的基本测试浅谈

    教您使用UniqueIdentifier选取SQL Server主键

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。