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

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

  背景
  相信大家在日常的工作中,一定遇到过以下的某个场景:  前端需要选择某些字段,去展示不同字段下的信息,如果在字段和方法没有绑定的情况下,如何调用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中,最基础,也是最核心的内容,同样也是最有用的。然而实际的工作当中,我们接触到的机会少之又少,所以我们需要自我提升,将这些手段融会贯通。本文涉及的知识很小一部分反射知识,但是对应经常与表单,表格打交道的后端程序员来说,却非常有用,赶紧用起来吧~~
大思政课走进香山革命纪念馆,从红色文化中汲取奋进力量10月1日,清华大学日新马理2班全体同学参加学校共溯峥嵘路,喜迎二十大系列主题社会实践,前往香山革命纪念馆开展党史学习教育实践活动。本次实践活动由校党委副书记许庆红带队,包括日新马回不去的故乡那座掏空了的煤矿如今变得空荡荡的故乡主街区萧红的呼兰河传以其自然流畅轻松的笔调,为我们讲述了日寇铁蹄蹂躏下的东北人民,那种麻不不仁的闭塞生活,故乡那个东北小镇带给她许多五味杂陈的回忆。眼下我的故乡国资委进一步做好2022年服务业小微企业和个体工商户房屋租金减免工作新华社北京10月13日电国务院国资委日前发出关于进一步做好2022年服务业小微企业和个体工商户房屋租金减免工作的通知,要求各中央企业和地方国有企业进一步提高站位,不折不扣将房租减免大思政课在福建三明,感受红色文化与绿色发展我和我的祖国,一刻也不能分割,无论我走到哪里,都流出一首赞歌嘹亮婉转的歌声从福建三明的绿水青山中传出,在三明的红色沃土上回荡,一唱一和,吟出青春的朝气一言一句,饱含对祖国的深情。党杨开慧保姆之女孙燕,不想下乡求助毛主席,主席为何为她破例?满是藏品的房间里,一个年迈的老者自称是毛主席的七叔公,让四周的警卫们把这些珍贵的古董搬到毛主席的房间里去。门外的毛主席听到这一消息后脸色骤变,冲了进去,呵斥自己的七叔公这是发生在电美国龙飞船载4名宇航员返回地球新华社洛杉矶10月14日电(记者谭晶晶)搭载美欧4名宇航员的美国太空探索技术公司龙飞船14日返回地球,降落在美国东南部佛罗里达州附近海面。在国际空间站停留近6个月后,龙飞船于美国东大国崛起!中国有哪些技术已经超过了美国,位于全球前列呢?大国崛起,带动世界格局的不断变化,中国目前在科技领域的发展有目共睹,那么我国在追赶发达国家的过程中,有哪些技术,已经超过了美国这个世界第一,位于全球前列呢?西方国家对很多高新技术实龙飞船首次快速返回!Crew4乘组结束170天绕地1。16亿千米太空旅行Crew4自由号(Freedom)龙载人飞船返回舱成功溅落北京时间2022年10月15日0455(下同北京时间),美国航空航天局(NASA)SpaceXCrew4自由号(Freed(科技)我国成功发射遥感三十六号卫星(科技)我国成功发射遥感三十六号卫星10月15日3时12分,我国在西昌卫星发射中心使用长征二号丁运载火箭,成功将遥感三十六号卫星发射升空,卫星顺利进入预定轨道,发射任务获得圆满成功油烟机新技术,拥有空气净化功能的米家智能净烟机P1到底有多强?一生活中隐形的健康杀手PM2。5可能很多人都不是特别重视PM2。5的危害,觉得太过于渺小,几乎肉眼不见的东西,到底能有多大的危害?!但其实不然,PM2。5因质量极小,可以长期飘散到事关房屋租金减免!国资委发文国资委进一步做好2022年服务业小微企业和个体工商户房屋租金减免工作国务院国资委日前发出关于进一步做好2022年服务业小微企业和个体工商户房屋租金减免工作的通知,要求各中央企业和地
除夕年夜饭,记得1要全,2要吃,3不用,留4样,迎春接福过大年新年美食市集金虎辞旧岁,黑兔迎新春,农历黑兔年的脚步已经离我们越来越近,1月21日就是大年三十除夕夜。明年的兔年有384天,而且明年的兔年是癸卯年,按照传统五行说法,癸水为黑,而卯来延庆过大年丨华彩夜长城,增添别样年夜味距离春节越来越近,精彩纷呈的节日活动也越来越多。1月21日至27日(农历除夕至正月初六),八达岭夜长城开放。这将是八达岭夜长城首次在春节期间开放,届时,夜长城还将上新特色花会展演活江西喝酒怪象茅台不上桌,也不常喝四特酒,却爱这5款佳酿说到庐山相信大家都不陌生,毕竟我们经常把终于漏出庐山真面目挂在嘴边,这里的庐山就在风景优美的江西。小时候小编一直不理解为什么要用漏出庐山真面目这句话表示终于见到了一个人的全貌,直到500万!济南再发文旅惠民消费券迎新春,1月21日起可领!中国山东网感知山东1月17日讯新春佳节将至,泉城年味十足。济南市文化和旅游局组织文旅行业系统以冬游济南福满泉城为主题,举办2023泉城新春贺年会,并计划于春节期间面向全体在济人员发北方仙城,蓄势腾飞!胶东在线1月17日讯(记者王向荣)今来海上升高望,不到蓬莱不是仙。蓬莱,素有人间仙境的美誉,至今已有2000多年的历史,是古登州治所所在地。古登州蓬莱底蕴十足,新时代蓬莱潜力无限。除了去三亚,冬天去哪里温暖又好玩,云南这四座城市千万别错过疫情放开的季节刚好在冬天,毫无意外,三亚又火出了圈。随之而来的是高房价和高票价,热搜上甚至爆出三亚酒店一晚上18万元的天价。如果不是非去不可的理由,祖国那么大,江山那么美,何必单恋春节汉阳有哪些好玩的?够好逛!以下内容来自长江日报时隔三年,归元寺终于在兔年新春重新开放。到汉阳祈福,逛归元庙会,是武汉人过年的传统。而这里的景观,早已大篇幅刷新,备足了让大家来汉阳好好玩的理由去全新的琴台,观上央视上热搜,这个地球上的美丽伤痕,却有水声如万马奔腾1月8日,广西百色通灵大峡谷登上央视,CCTV4中国地名大会以短片的形式,向观众介绍通灵大峡谷喀斯特地貌的神奇,通天彻地灵动飘逸的景象。同一天,广西百色通灵大峡谷也登上微博热搜。通2023海口三角梅花展开园沉浸式体验赏花七部曲新海南客户端南海网南国都市报1月17日消息(记者丁文文)新的一年从这场浪漫花展开始吧!1月17日上午,以花园村庄幸福生活为主题的2023海口三角梅花展在三角梅共享农庄开幕。活动现场冷冷冷!肇庆最低气温0。5,这些地方结冰了!受强冷空气影响,肇庆气温骤降,这些地方变成冰雪世界,漫山遍野的树木银装素裹,晶莹剔透的冰挂景观引人注目。封开县麒麟山1月16日早晨,封开县渔涝镇麒麟山出现今年首场雾凇冰挂景观,漫山养护海洋建设海洋牧场海南分界洲岛海域投放复合生物礁来源央视新闻客户端2023新年伊始,在海南陵水分界洲岛海域,工作人员潜入海底,组装苗圃铁架,固定珊瑚幼苗。据介绍,水下珊瑚礁投放工作于1月10日开始投放,16日完成。我们前期已经对