反射能做什么
- 对于任意一个类,都能知道这个类的所有属性和方法;
- 对于任意一个对象,都能调用它的任意一个方法和属性。
反射常用的类
Constructor类: 提供类的构造方法的信息及对它的访问权限。 Field类: 提供类或接口上的字段的信息,及对它的动态访问权限。 Method类: 提供类或接口上某个方法的信息。
Class类
面向对象的世界里,万事万物都是对象。类也是对象,它是java.lang.Class
类的示例对象。
Class类没有公共构造方法,那怎么创建Class
类的对象?
创建Class
类对象的三种方法
- 使用类的
class
属性
Class c = Demo.class
- 使用
Class
类的forName
方法
try {
Class c = Class.forName("xin.zhuyao.gzh.test20200722.Demo");
//使用Class类的forName方法创建Class对象时,需要捕获ClassNotFoundException
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
- 使用
Object
对象的getClass
方法
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
做数据处理,难道我们要一个一个get
和set
吗?我们可以写一个工具类。
用途
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
感兴趣的小伙伴可以去了解下。