反射到底有什么作用,能帮我们干些什么呢?

2022-01-18 16:01:14 浏览数 (1)

反射能做什么

  • 对于任意一个类,都能知道这个类的所有属性和方法;
  • 对于任意一个对象,都能调用它的任意一个方法和属性。

反射常用的类

Constructor类: 提供类的构造方法的信息及对它的访问权限。 Field类: 提供类或接口上的字段的信息,及对它的动态访问权限。 Method类: 提供类或接口上某个方法的信息。

Class类

面向对象的世界里,万事万物都是对象。类也是对象,它是java.lang.Class类的示例对象。 Class类没有公共构造方法,那怎么创建Class类的对象?

创建Class类对象的三种方法

  • 使用类的class属性
代码语言:javascript复制
Class c = Demo.class
  • 使用Class类的forName方法
代码语言:javascript复制
try {
    Class c = Class.forName("xin.zhuyao.gzh.test20200722.Demo");
    //使用Class类的forName方法创建Class对象时,需要捕获ClassNotFoundException
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}
  • 使用Object对象的getClass方法
代码语言:javascript复制
Demo demo = new Demo();
Class c = demo.getClass();

虽然有3种方法但是它们创建的反射对象是完全相同的,也就是说:一个类只能有一个反射对象,有兴趣的小伙伴可以测试下。

Class类的主要方法

构造方法

代码语言:javascript复制
//获得所有权限为public的构造方法
Constructor<?>[] getConstructors();

//获得权限为public的指定构造方法
Constructor<T> getConstructor(Class<?>... parameterTypes);

//获得所有构造方法,按声明顺序返回
Constructor<?>[] getDeclaredConstructors();

//获得指定构造方法
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes);

方法

代码语言:javascript复制
//获得所有权限为public的方法
Method[] getMethods();

//获得权限为public的指定方法
Method getMethod(String name, Class<?>... parameterTypes);

//获得所有方法,按声明顺序返回
Method[] getDeclaredMethods();

//获得指定方法
Method getDeclaredMethod(String name, Class<?>... parameterTypes);

成员变量

代码语言:javascript复制
//获得权限为public的成员变量
Field[] getFields();

//获得权限为public的指定成员
Field getField(String name);

//获得所有成员变量,按声明顺序返回
Field[] getDeclaredFields();

//获得指定成员变量
Field getDeclaredField(String name);

说明:通过getFields()getMethods()获得权限为public的成员变量和方法时,将包含从超类中继承到的成员变量和方法;通过方法getDeclaredFields()getDeclaredMethods()只能获得本类中定义的所有成员变量和方法。

这里就不介绍获取构造方法获取方法了,如果感兴趣的小伙伴可自行去查看。这里只介绍获取成员变量也就是Field这个类

Field类的主要方法

方法

代码语言:javascript复制
//获得该成员变量的名称
String getName();

//获得表示给成员变量类型的Class对象
Class<?> getType();

//获得指定对象中成员变量的值,返回Object型
Object get(Object obj);

//将指定对象中成员变量的值设置为obj
void set(Object obj, Object value);

//获得指定对象中类型为int的成员变量
int getInt(Object obj);

//将指定对象种类型为int的成员变量的值设为i
void setInt(Object obj, int i)

//。。。八种数据类型都有就不一一列出了

//此方法可以设置是否忽略权限限制直接访问private等私有权限的成员变量
void setAccessible(boolean flag);

写了这么多,我们在什么时候能用到呢? 现在比如有两个类,好比方说DO(数据库类)和DTO(数据处理专用类),它们之间很多字段都很相同,现在我要吧DO中的数据传给DTO做数据处理,难道我们要一个一个getset吗?我们可以写一个工具类。

用途

DemoDO

代码语言:javascript复制
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DemoDO {

    private Integer id;

    private String name;

    private Integer sex;
    
    private String password;
}

DemoDTO

代码语言:javascript复制
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DemoDO {

    private Integer id;

    private String name;

    private Integer sex;
    
}

工具方法

代码语言:javascript复制
public static <S,T> T copyProperties(S source, Class<T> tClass){
    try {
        Class<?> sClass = source.getClass();
        T target = tClass.newInstance();
        if (null == source){
            return target;
        }
        Field[] fields = tClass.getDeclaredFields();
        for (Field field : fields) {
            try {
                Field declaredField = sClass.getDeclaredField(field.getName());
                field.setAccessible(true);
                declaredField.setAccessible(true);
                field.set(target,declaredField.get(source));
            } catch (NoSuchFieldException e) {
                log.info("没有该字段:{}",field.getName());
            }
        }
        return target;
    } catch (InstantiationException | IllegalAccessException e) {
        throw new RuntimeException(String.format("%s must declaring none arguments constructor!", tClass.getTypeName()));
    }
}

测试

代码语言:javascript复制
public static void main(String[] args) {
    DemoDO demoDO = DemoDO.builder().id(1).name("zy").sex(1).password("123").build();
    DemoDTO demoDTO = copyProperties(demoDO, DemoDTO.class);
    System.out.println(demoDTO.toString());
}

结果

代码语言:javascript复制
DemoDTO(id=1, name=zy, sex=1)

当然这个只是例子,其实spring早就提供了这方面的工具了了,BeanUtils.copyProperties感兴趣的小伙伴可以去了解下。

0 人点赞