范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

简简单单的反射和詹杜库放在一起就能好玩了吗?

  背景
  相信大家在日常的工作中,一定遇到过以下的某个场景:  前端需要选择某些字段,去展示不同字段下的信息,如果在字段和方法没有绑定的情况下,如何调用get方法呢?  如果有一张横转纵的表,存储的do都是实际的字段名称,那么如何转化成实体类对应的get、set方法去执行操作呢?  如果我想根据方法名称去调用对象的某个方法呢?
  相信有些基础的程序员会立刻想到使用反射就好了,没错,就是这么简单,但是每用到一次,咱们就去写一次也是比较麻烦的,所以我们可以将它封装成工具类,用的时候直接去调用就好了。  实现
  目前我在工具类实现了三个方法,分别是:  根据属性名调用对象get方法  根据属性名调用对象的set方法  根据方法名调用方法  根据属性名调用对象get方法
  实现逻辑:  获取对象的class  获取对象的所有属性  获取对象的声明方法  遍历属性  匹配方法  invoke执行该方法  返回方法的返回值  /**          * 根据属性名获取属性值          *          * @return java.lang.String          * @Param filedName          * @Param obj          * @Date 2022/12/15 15:06          * @Author wjbgn          **/         public static String getObjField(String filedName, Object obj) {             AtomicReference value = new AtomicReference<>();             Class<?> aClass = obj.getClass();             // 获取所有属性             Field[] declaredFields = aClass.getDeclaredFields();             // 获取所有方法             Method[] declaredMethods = aClass.getDeclaredMethods();             Arrays.stream(declaredFields).forEach(filed -> {                 if (filed.getName().equals(filedName)) {                     // 属性存在,尝试获取属性,调用get方法,此处get方法需要组装                     Arrays.stream(declaredMethods).forEach(method -> {                         if (method.getName().toLowerCase().equals("get" + filedName)) {                             try {                                 // 执行方法                                 Object invoke = method.invoke(obj);                                 value.set(invoke == null ? null : invoke.toString());                             } catch (Exception e) {                                 throw new RuntimeException(e);                             }                         }                     });                 }             });             return value.get();         }  根据属性名调用对象的set方法
  实现逻辑:  获取对象的声明方法  遍历方法  匹配方法名称  invoke执行该方法  /**          * 根据属性名设置属性值          *          * @return void          * @Param filedName 字段名          * @Param value 字段值          * @Param obj 对象          * @Date 2022/12/15 14:41          * @Author wjbgn          **/         public static void setObjField(String filedName, String value, Object obj) {             Class<?> aClass = obj.getClass();             Arrays.stream(aClass.getDeclaredMethods()).forEach(method -> {                 if (method.getName().toLowerCase().equals("set" + filedName)) {                     try {                         method.invoke(obj, value);                     } catch (IllegalAccessException e) {                         throw new RuntimeException(e);                     } catch (InvocationTargetException e) {                         throw new RuntimeException(e);                     }                 }             });         }  根据方法名调用方法
  实现逻辑:  获取对象的所有方法 -> 不同于获取get、set,此处需要获取所有的方法,包括实现和继承来的。  遍历方法  匹配方法名称  invoke执行该方法  返回方法返回值  /**         * 根据方法名调用该方法         *         * @return java.lang.Object         * @Param filedName         * @Param obj         * @Date 2022/12/15 15:05         * @Author wjbgn         **/        public static Object invokeMethod(String filedName, Object obj) {            AtomicReference result = new AtomicReference<>();            Arrays.stream(obj.getClass().getMethods()).forEach(method -> {                if (method.getName().toLowerCase().contains(filedName)) {                    // 有方法包含该属性                    try {                        Object invoke = method.invoke(obj);                        result.set(invoke);                        return;                    } catch (Exception e) {                        throw new RuntimeException(e);                    }                }            });            return result.get();        }  测试准备基础代码
  使用一段代码来测试下我们的方法,首先准备一些基础类。
  背景是有三个小学生,分别是  詹姆斯  ,库里  ,杜兰特  ,每个人共有一些属性,如下所示:/**     * 学生类,每个学生可以跑,跳,投篮     */    static class Student implements PlayerActon {         private String name;         private String age;         private String team;         @FieldDesc(type = "exclusive", value = " learn exclusive skills >> ")        private String exclusive;        @FieldDesc(value = ""s phone num? I don"t know!")        private String phone;         public Student(String name, String age, String team, String phone) {            this.name = name;            this.age = age;            this.team = team;            this.phone = phone;        }         public Student() {         }         public String getExclusive() {            return exclusive;        }         public void setExclusive(String exclusive) {            this.exclusive = exclusive;        }         public String getName() {            return name;        }         public void setName(String name) {            this.name = name;        }         public String getAge() {            return age;        }         public void setAge(String age) {            this.age = age;        }         public String getTeam() {            return team;        }         public void setTeam(String team) {            this.team = team;        }         public String getPhone() {            return phone;        }         public void setPhone(String phone) {            this.phone = phone;        }         @Override        public String running() {            return " is running!";        }         @Override        public String jumping() {            return " is jumping!";        }         @Override        public String shooting() {            return " make a shot!";        }    }
  上面的实体类实现了一个接口  PlayerActon  ,里面是三个方法,表示运动员可以跑  ,跳  ,投篮  :    /**     * 动作接口     */    private interface PlayerActon {        /**         * 跑         */        String running();         /**         * 跳         */        String jumping();         /**         * 投篮         */        String shooting();    }
  除此之外,看到下面的两个属性,分别带有一个注解:  @FieldDesc(type = "exclusive", value = " learn exclusive skills >> ")  private String exclusive;   @FieldDesc(value = ""s phone num? I don"t know!")  private String phone;
  这里没什么别的含义,就是想在反射的时候,给这个属性赋默认值,在注解上面可以直接取值,比较方便。另外注解的属性还有一个  type  ,这个type用来指定当前的属性是专属  字段,因为不同的球员有不同的个性,我们通过这个类型判断下,如果是这个字段,那么要给上面的三个小学生赋不同的专属技能了:   /**     * 自定义注解,描述字段     */    @Documented    @Target({ElementType.FIELD, ElementType.METHOD})    @Retention(RetentionPolicy.RUNTIME)    private @interface FieldDesc {        /**         * 类型         */        String type() default "";         /**         * 字段描述         */        String value() default "";    } 复制代码
  既然说到了技能了,那就把技能枚举定义一下:      /**     * 技能枚举     */    public static enum SkillsEnum {        STAND_HAND("James", "STAND HAND!!!", "摊手"),        SHAKE_HEAD("Curry", "SHAKE HEAD!!!", "摇头"),        SHAKE_SHOULDERS("Durant", "SHAKE SHOULDERS!!!", "晃肩膀");        private String studentName;        private String skillsName;        private String skillsNameDesc;         SkillsEnum(String studentName, String skillsName, String skillsNameDesc) {            this.studentName = studentName;            this.skillsName = skillsName;            this.skillsNameDesc = skillsNameDesc;        }         public String getStudentName() {            return studentName;        }         public void setStudentName(String studentName) {            this.studentName = studentName;        }         public String getSkillsName() {            return skillsName;        }         public void setSkillsName(String skillsName) {            this.skillsName = skillsName;        }         public String getSkillsNameDesc() {            return skillsNameDesc;        }         public void setSkillsNameDesc(String skillsNameDesc) {            this.skillsNameDesc = skillsNameDesc;        }         /**         * 根据学生获取技能         *         * @return java.lang.String         * @Param student         * @Date 2022/12/15 14:21         * @Author wjbgn         **/        public static String getSkillsByStudent(Student student) {            for (SkillsEnum skillsEnum : SkillsEnum.values()) {                if (skillsEnum.getStudentName().equals(student.getName())) {                    return skillsEnum.getSkillsName();                }            }            return null;        }    }  准备main方法
  下面我们准备一个main方法,模拟一个场景:      /***     * 工具类测试样例     *     * @Param args     * @return void     * @Date 2022/12/15 15:10     * @Author wjbgn     **/    public static void main(String[] args) {        // 获取动作对应的结果,循环10次        for (int i = 0; i < 10; i++) {            try {                // 随机获取一个学生                Student student = studentList.get(new Random().nextInt(3));                // 随机获取一个动作                String action = actionList.get(new Random().nextInt(7));                // 打印下随机结果                System.out.println(getStudentField(action, student));                 // Thread.sleep(500L);            } catch (Exception e) {                throw new RuntimeException(e);            }        }    }
  如上所示,循环10次,分别调用  getStudentField  方法,方法后面会讲,这个方法就是为了获取学生的属性,但是我们从上面的代码看的出来,获取哪一个学生,获取学生的哪一个属性都是随机的,所以我们首先把这些属性和学生初始化一下,其中除了有字段属性  ,还有方法名称  : /**     * 动作集合     */    private static List studentList = new ArrayList<>();     /**     * 动作集合     */    private static List actionList = new ArrayList<>();     /**     * 初始化 动作集合,学生     * 这里面都使用字段的名称,不使用get、set方法     */    static {        // 获取球员的年龄        actionList.add("age");        // 获取球队        actionList.add("team");        // 获取电话        actionList.add("phone");         // 学习/使用专属动作        actionList.add("exclusive");         // 跑        actionList.add("running");         // 跳        actionList.add("jumping");         // 投篮        actionList.add("shooting");         studentList.add(new Student("James", " 37 years old", " From the Los Angeles Lakers", ""));        studentList.add(new Student("Curry", " 34 years old", " From the Golden State Warriors", ""));        studentList.add(new Student("Durant", " 33 years old", " From the Brooklyn Nets", ""));    }
  有了上面的初始化,我们就可以随机的调用  getStudentField  方法,步骤:首先将学生名字返回拼接到字符串  通过  属性名称  和学生对象  调用前面封装好的ObjectDynamicUtil.getObjField  方法如果没获取到属性,表示  属性为空  或者不是属性,是方法  去调用  setStudentField   方法,如果返回有值,则成功,再次ObjectDynamicUtil.getObjField  获取一次如果仍然是空,那么就调用前面封装好的  ObjectDynamicUtil.invokeMethod  ,按属性调用方法。返回结果      /***     * 动态获取学生属性     *     * @Param     * @return void     * @Date 2022/12/15 11:23     * @Author wjbgn     **/    private static String getStudentField(String filedName, Student student) throws NoSuchFieldException {        String msg = student.getName();        // 获取属性值        String value = ObjectDynamicUtil.getObjField(filedName, student);        if (value == null || value == "") {            // 如果获取属性是空怎么办?设置一个值进去            setStudentField(filedName, student);            // 设置值后,再次执行get方法            value = ObjectDynamicUtil.getObjField(filedName, student);        }        // 调用学生实现的动作接口方法        if (value == null) {            value = (String) ObjectDynamicUtil.invokeMethod(filedName, student);        }        msg += value;        return msg;    }
  下面看下设置学生属性值的方法:  setStudentField  ,步骤:获取学生对象class  根据  属性名  获取class的属性根据属性获取注解  FieldDesc  ,即前面自定义的注解如果注解类型是  exclusive  ,就根据学生从枚举类获取专属技能拼装结果并调用  ObjectDynamicUtil.setObjField  设置对象属性    /***     * 动态设置学生属性     *     * @Param     * @return void     * @Date 2022/12/15 11:23     * @Author wjbgn     **/    private static void setStudentField(String filedName, Student student) throws NoSuchFieldException {        Class<? extends Student> studentClass = student.getClass();        Field declaredField = null;        try {            declaredField = studentClass.getDeclaredField(filedName);        } catch (NoSuchFieldException e) {            return;        } catch (SecurityException e) {            throw new RuntimeException(e);        }        FieldDesc annotation = declaredField.getAnnotation(FieldDesc.class);        String value = annotation.value();        String finalValue = value + (annotation.type().equals(filedName) ? SkillsEnum.getSkillsByStudent(student) : "");        ObjectDynamicUtil.setObjField(filedName, finalValue, student);    }  查看结果
  到此为止,所有的代码都准备完毕了,记得把main方法的  Thread。sleep  注释放开,看到的结果更加直观。
  此处注释是因为在码上掘金导致代码不能运行,不知道码上掘金是什么原因?
  结果如下图所示:
  如上所示,看到不同的学生可以做不同的事,展示不同的属性,都是随机动态获取的。  总结
  反射  是java中,最基础,也是最核心的内容,同样也是最有用的。然而实际的工作当中,我们接触到的机会少之又少,所以我们需要自我提升,将这些手段融会贯通。本文涉及的知识很小一部分反射知识,但是对应经常与表单,表格打交道的后端程序员来说,却非常有用,赶紧用起来吧~~
美文赵丽宏秋天的树秋风在大地上游荡。夏日的酷暑像一群惊惶失措的野兽,在悄然而至的秋风里一哄而散,逃遁得不知去向。秋天是我最喜欢的季节。年轻时代生活在乡村的那几年,我真正理解了成熟和收获与秋天的关系。适合秋天小住几天的小村镇,累了,就出去走走吧四季中,最爱的季节就是秋天。因为它足够绚烂,所有颜色都在这个季节,变得不再吝啬,尽情地在大地这块画板上渲染创作。所以,一定要抽个时间,好好地感受秋天。不如就去一个宁静的古村落吧。好晒秋!丰收的季节,婺源告诉你什么是真正的秋天婺源位于江西省,每年34月份,婺源的油菜花吸引着一大波游客的目光,这里油菜花的著名程度可以说是人尽皆知了,那你知道婺源的晒秋吗?婺源篁岭的晒秋大概就是秋天最正确的打开方式了,秋天是秋天吃点柚子有好处,但并非所有人都适合,这3类人请少碰说到柚子相信大家应该是不算陌生的,当下正是柚子大量成熟上市的季节,所以应季吃点柚子能给身体带来很多好处。虽然当代的农业种植技术已经足够发达了,反季水果和蔬菜也受到了人们的喜欢,但是年轻时每天都喝2两白酒的人如今怎么样了?70岁大爷说出真相年轻时每天都喝2两白酒的人如今怎么样了?70岁大爷说出真相老话都说无酒不成席,无酒不成宴。白酒作为国人宴席中的必备单品之一,很多朋友只要吃饭聚会,那必定是要喝上一两杯的,不管是借酒为什么年轻人都不愿意换新手机了?屏幕前的你有多久没有换新手机了?一年两年还是三年?从当初割肾都要买的新手机,到现在的Iphone还能坚持再战两年。那么是什么治好了年轻人的换机焦虑呢?答案因为穷啊。10年前第一批9当代年轻人为什么越来越不想生娃了?在我刚出生那个年代,每个家庭里总会有很多个孩子,独生子女家庭真的是少之又少。因此在那个时候,国家为了控制人口数量,出台了计划生育政策。还记得在我五岁的时候,我弟弟出生之后的一个月,新一代城市尖叫地标,如何征服年轻旅行者?本文来自微信公众号空间秘探(IDMESPACE007),作者郑豫舟。近日亮相的上海苏河湾万象天地,推出了名为UPWEGO!迈上新景象艺术项目,并邀请国内外一众明星潮人对此发声。该艺不想移民火星的企业家不是好的工程师埃隆马斯克秋日生活打卡季上一次关注到埃隆马斯克的消息,还是他的八卦新闻,说他和谷歌创始人的老婆有婚外情云云,当然后来怎么样了,作为吃瓜群众就只吃吃瓜而已。而这个瓜,也勾起我好奇对埃隆马斯克的长春欧亚集团股份有限公司党委书记董事长曹和平做一名优秀的企业当家人在吉林省提起他,人们总会第一时间想到欧亚集团这艘商业航母在欧亚集团提到他,员工们对他创业守业的故事如数家珍他就是曹和平,长春欧亚集团股份有限公司党委书记董事长,一名有46年党龄的老中国电子信息产业集团有限公司集成电路(IC)半导体(Microelectronics),是一种由硅和锗(Ge)等半导体材料制成的小型无源器件,它与芯片传感器计算机和电子设备等其他电子设备结合在一起,构成一个庞大电子信息产业链
科普笔记本电脑外接显示器,如何设置刷新率?看完你就知道了如今游戏制作水平越来越高,随便打开一个网络游戏,无论是玩法设计还是场景刻画,还是地图设计,都是细节程度拉满,这多少让笔记本电脑的小屏幕有点HOLD不住了于是,为了进一步提升游戏体验怪物猎人崛起曙光第一弹免费更新来啦8月10日,怪物猎人崛起曙光迎来第一弹免费更新,虽然还是有点挤牙膏,但整体来看还是比较有诚意的,那让我们来看看,都更新了哪些内容吧新怪物新原野怪物方面。本次更新增加了四只怪物,分别国服地下城811版本怎么玩?整体减负新增装备高级副本国服会在8月11日更新机械战神全新版本,主体内容都会在此版本更新。在8月25日对贵族机要副本进行调整降低入门门槛降低门票购买名望限制名望限制变更为平均小队名望等。下面小编会从减负装热血传奇开天是什么武器?屠龙不如开天?哈喽大家好,今天小编又来和大家分享传奇新资讯啦,今天来和大家说说传奇极少数的大战士,也只有较高的战力才能体验到战士的爆发。想要拥有这样的爆发肯定要付出不同的代价,比如开天武器在当时9。27生存猎导灵器盟约以及配装最近发布了两个视频,有的小伙伴私聊问我生存猎导灵器配装相关问题的,还有的小伙伴说为什么他的生存猎就打不出伤害炸弹刷新的非常少,今天我就详细的给大家介绍一下生存猎相关配装盟约导灵器和iPhone不一样的叫醒服务对于每天早上都得用闹钟叫醒起床的人来说,一成不变的闹钟早已是世界上最难听的声音了,今天小编和大家分享一个iPhone不一样的闹钟。第一步,点开快捷指令第二步点击创建个人自动化第三步红米K50至尊版真的是至尊配置吗?红米在K30时代出现过至尊版,如K30S至尊纪念版K30至尊纪念版。不过在K30至尊纪念版上,却因为天玑1000Plus的发热而翻车,有人甚至觉得它比骁龙还热。那么到了红米K40时正式确定!杜锋提拔2米08潜力锋线,天赋不输张镇麟,或接班周鹏广东宏远随队记者关辛谈到了下赛季哪些球员值得期待时,除了张昊张皓嘉徐昕和张明池之外,还透露18岁的黄明依打完耐高全国赛之后,下赛季将会正式升入一队,大家可以对他有所期待。广东宏远今梦想那些足以支撑你走很远的句子一我深怕自己本非美玉,故而不敢加以刻苦琢磨,却又半信自己是块美玉,故而不肯庸庸碌碌,与瓦砾为伍。心有天地,山在的烦恼也不过一隅,经常看一看别人,低个头也就能看到自己了。这是杀破狼里面总决赛场均得分30有多难?NBA历史上仅6人做到,詹科皆无法入榜如果说季后赛是球星的试金石,那么总决赛就是超级球星的敲门砖。想在这种最高级别的竞技场上打出场均30的表现,这是非常困难的,纵观NBA的76年历史长河也就只有6人做到过。第6凯文杜兰7月特斯拉并没有卖不动,只是优势正在被蚕食不知为何,放眼整个行业,对于特斯拉这样一家流量与声量均颇高的明星车企,总是充斥着各种吹捧与看衰并存的言论。6月,当其在华狂售新车7。8万辆,ModelY单车型销量更是一举突破5万辆