美文网首页
浅谈java反射【原创】

浅谈java反射【原创】

作者: 程序员不会写代码 | 来源:发表于2019-06-22 14:57 被阅读0次

    参考书籍《疯狂java》

    反射的用处

    反射能获取对象的属性,以及对象的属性值,甚至是私有的方法,这个一般是用在框架的,或者是权限校验,参数校验等框架的设计,反射在面试也比较常见,但是在实际的项目中,每个开发者接触的机会不多,一般都是大牛们在负责写这些,利用反射写一些通用组件等等,来解决发杂需求或者给其他开发者提供组件

    提问

    如何通过反射获取UpdateCheckRequestType中子对象list里面的inspectionItemId以及checkDTO中的description

    public class UpdateCheckRequestType  {
        private CheckDTO checkDTO;
        private List<InspectionDTO> list;
    }
    
    public class CheckDTO {
        private String id;
        private String description;
    
    public class InspectionDTO {
        private String inspectionItemId;
        private String inspectionValue;
    
    

    首先要明确一点,在反射获取属性的过程中一定是先有class,然后才有属性,不多说上代码

     public static void main(String[] args) {
            // 准备数据
            CheckDTO dto = new CheckDTO();
            dto.setDescription("123434");
            InspectionDTO inspectionDTO = new InspectionDTO();
            inspectionDTO.setInspectionItemId("123234");
            List<InspectionDTO> list = new ArrayList<>();
            list.add(inspectionDTO);
            UpdateCheckRequestType type = new UpdateCheckRequestType();
            type.setList(list);
            type.setCheckDTO(dto);
        }
    

    有些伙伴会问,直接new UpdateCheckRequestType不就完事了吗?为啥还要给里面的子对象赋值?你如果直接new出来,没有赋值,拿到的子对象就是null,通过这个子对象去获取子对象里面的属性是获取不到的,会抛出空指针异常,还是那句话,现有class再有属性,既然class都是null,那么何来的属性呢?

      // 获取type的属性
            Field[] fields = type.getClass().getDeclaredFields();
            System.out.println(fields[0].getName());
    输出结果
    checkDTO
    
    1. 这里要说下的是getDeclaredFields,getDeclaredField,getFields,getField
      首先不包含s的获取的是单个属性的,需要提前知道属性的名字,而且当不存在时候会有异常抛出
    2. 不含有Declared的方法只能获取共有属性,而Declared可以获取私有的属性,我们实体类中的属性都是私有,当然还有getMethod等等规则和上面是一样的
      从这里看到我们已经拿到了type中的子对象checkDTO,对type来说checkDTO是其中的一个属性,因此我们这里可以直接或取checkDTO,下面获取checkDTO中的Description的值
       // 获取type的属性
            Field[] fields = type.getClass().getDeclaredFields();
            // 设置私有属性可以访问
            fields[0].setAccessible(true);
            // 获取checkDTO的实际对象
            Object value = fields[0].get(type);
            System.out.println(value.toString());
    
    如果缺少设置私有属性允许访问这一步会抛出如下异常
    Exception in thread "main" java.lang.IllegalAccessException: Class com.lightkits.mes.dto.equipment.FanShe can not access a member of class com.lightkits.mes.dto.equipment.UpdateCheckRequestType with modifiers "private"
        at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
        at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
        at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
        at java.lang.reflect.Field.get(Field.java:390)
        at com.lightkits.mes.dto.equipment.FanShe.main(FanShe.java:28)
    
    输出结果如下
    CheckDTO(id=null, description=123434, equipmentId=null, remark=null, collector=null, taskStatus=null, taskNum=null)
    

    OK,离目标又进了一步,接下来反射获取description

       Field[] fields1 = value.getClass().getDeclaredFields();
            System.out.println(fields1[1].getName());
    输出结果
    description
    接下来获取description的值 套路是一样的
     // 获取checkDTO的实际对象
            Object value = fields[0].get(type);
            System.out.println(value.toString());
            Field[] fields1 = value.getClass().getDeclaredFields();
            System.out.println(fields1[1].getName());
            fields1[1].setAccessible(true);
            System.out.println(fields1[1].get(value));
    值得注意的是在获取子对象的属性值的时候get里面放置的是子对象
    输出结果
    123434
    

    ok 既然有get 那就必定有set

    Object value = fields[0].get(type);
            System.out.println(value.toString());
            Field[] fields1 = value.getClass().getDeclaredFields();
            System.out.println(fields1[1].getName());
            fields1[1].setAccessible(true);
            System.out.println(fields1[1].get(value));
            fields1[1].set(value, "你好");
            System.out.println(fields1[1].get(value));
    输出结果对比
    123434
    你好
    

    set可以用来改变属性值,这个在sqlhelp这个框架里面用到了,有兴趣的可以去了解下,总之来说get和set在反射中使用频率比较高
    如果想获取list对象里面属性对象的属性值这个就和上面的套路是一样的了,直接上代码

      // 获取type的属性
            Field[] fields = type.getClass().getDeclaredFields();
            // 设置私有属性可以访问
            fields[1].setAccessible(true);
            // 在强转之前需要事先预判,否则会抛出异常
            List<?> list1 = (List<?>)fields[1].get(type);
            Object o = list1.get(0);
            Field[] fields1 = o.getClass().getDeclaredFields();
    

    这里是拿到子对象的属性,能拿到属性,就可以解决其他问题,套路和上面是一样
    在项目中的多数情况下是要去拿属性上的注解,根据属性注解去做操作,使用的方法是

      Field[] fields1 = o.getClass().getDeclaredFields();
            Annotation[] annotations = fields[0].getAnnotations();
            System.out.println(annotations.length);
            System.out.println(annotations[0].annotationType());
    结果如下
    1
    interface javax.validation.Valid
    

    总结:反射面试中经常问,java的底层也依赖,比较重要,进行反射切记先有class才有属性,如果class是null那就啥都没得

    相关文章

      网友评论

          本文标题:浅谈java反射【原创】

          本文链接:https://www.haomeiwen.com/subject/ruomqctx.html