浅谈java反射【原创】

2019-06-22  本文已影响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那就啥都没得

上一篇下一篇

猜你喜欢

热点阅读