反射是java编程的灵魂,在用反射之前有几个类需要了解:Class,Method,Feild,Constructor,在demo中演示这些类中比较常用的方法,然后用反射实现copy对象的封装类来说明反射的微妙。
1、常用方法:
public class ReflectDemo {
/** Class */
@Test
public void testClass() throws Exception{
Class<?> claz = People.class;
// 1、getMethods(), 获取所有方法,包括notify等从Object继承的方法
Method[] methods = claz.getMethods();
Arrays.asList(methods).forEach(method -> System.out.println(method.getName()));
// 2、getMethod(String name, Class<?>... parameterTypes), 方法名及参数列表
Method method = claz.getMethod("setName", String.class);
System.out.println(method.getName());
// 3、getClassLoader(), 加载器
System.out.println(claz.getClassLoader());
// 4、newInstance(), 获取实例
Object instance = claz.newInstance();
if (instance instanceof People) {
People people = (People) instance;
people.setAddress("广东深圳");
System.out.println(people);
}
System.out.println("------------Field-------------");
// 5、getFields(), 获取共有属性字段
Field[] fields = claz.getFields();
Arrays.asList(fields).stream().forEach(field -> System.out.println(field.getName()));
// 6、getDeclaredFields(), 获取所有字段,包括私有
Field[] declaredFields = claz.getDeclaredFields();
Arrays.asList(declaredFields).stream().forEach(field -> System.out.println(field.getName()));
System.out.println("------------Constructor-------------");
// 7、getConstructors(), 获取构造方法
Constructor<?>[] constructors = claz.getConstructors();
Arrays.asList(constructors).stream().forEach(constructor -> System.out.println(constructor.getParameterCount()));
}
/** Method */
@Test
public void testMethod() throws Exception{
People people = new People("11001", "张三", "广东深圳", "程序员");
Class<?> clazz = people.getClass();
Constructor<?> constructor = clazz.getConstructor(String.class, String.class, String.class, String.class);
System.out.println(constructor.getName());
Method action = clazz.getMethod("action", String.class, String.class, String.class);
// 1、getName(), 方法名称
String name = action.getName();
System.out.println(name);
// 2、getParameterCount(), 参数数量
int parameterCount = action.getParameterCount();
System.out.println(parameterCount);
// 3、getParameterTypes(), 参数类型
Class<?>[] parameterTypes = action.getParameterTypes();
Arrays.asList(parameterTypes).stream().forEach(para -> System.out.println(para.getName()));
// 4、getReturnType(), 获取返回类型
Class<?> returnType = action.getReturnType();
System.out.println(returnType.getName());
// 5、getDeclaredAnnotations(), 获取使用的注解
Annotation[] declaredAnnotations = action.getDeclaredAnnotations();
System.out.println(declaredAnnotations.length);
// 6、改变对象的值
Method setAddress = clazz.getMethod("setAddress", String.class);
setAddress.invoke(people, "北京市海淀区");
System.out.println(people);
System.out.println("***** and so on *****");
}
/** Field */
@Test
public void testField() throws Exception{
People people = new People("11001", "张三", "广东深圳", "程序员");
Class<?> clazz = people.getClass();
// 1、getField(), 只能获取共有字段
Field field = clazz.getField("work");
Object work = field.get(people);
System.out.println(work);
// 2、getDeclaredField(), 可以获取包括私有字段
Field address = clazz.getDeclaredField("address");
// 设置访问权限
address.setAccessible(true);
Object o = address.get(people);
System.out.println(o); // out -> 广东深圳
}
}
2、很多情况下,在java编程中可能会遇到VO,DO对象相互转换的情况,同时两个实体类的字段比较相似,当然可以通过写setter方法来手动设置(试想有几十个字段的时候呢),这里通过反射实现一个封装,简化冗余的set赋值:
public class CopyDemo {
@Test
public void testCopy() throws Exception{
StudentDO studentDO = new StudentDO(1101, "张三", "2015018", 98.5, "man", "football", 25);
StudentVO studentVO = new StudentVO();
// studentDO -> studentVO
copyUtils(studentDO, studentVO);
System.out.println(studentVO);
}
private void copyUtils( StudentDO studentDO, StudentVO studentVO) throws Exception{
Class<?> clazzVO = studentVO.getClass();
Class<?> clazzDO = studentDO.getClass();
Method[] methodsVO = clazzVO.getMethods();
for (Method methodVO : methodsVO) {
// VO的set方法
String nameVO = methodVO.getName();
if (!nameVO.startsWith("set")) {
continue;
}
// 获取VO参数类型
Class<?>[] parameterTypes = methodVO.getParameterTypes();
if (parameterTypes.length < 1) {
continue;
}
Class<?> paraType = parameterTypes[0];
// DO的get方法
String nameDO = "get" + StringUtils.toUpperCase(nameVO.charAt(3) + "") + nameVO.substring(4);
Method methodDO = clazzDO.getMethod(nameDO);
// 获取DO返回类型
Class<?> returnType = methodDO.getReturnType();
// 通过get获取值
Object invokeValue = methodDO.invoke(studentDO);
// 按理说returnType和paraType类型一致, 如果不一致判断后转换即可
if (returnType.getName().equals(paraType.getName())) {
methodVO.invoke(studentVO, invokeValue);
}
}
}
}
两个实体类(除了雷名不同,其他先设定为相同)
StudentVO.java:
public class StudentVO {
private Integer id;
private String name;
private String sno;
private Double score;
private String sex;
private String hobby;
private Integer age;
public StudentVO() {
}
public StudentVO(Integer id, String name, String sno, Double score, String sex, String hobby, Integer age) {
this.id = id;
this.name = name;
this.sno = sno;
this.score = score;
this.sex = sex;
this.hobby = hobby;
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSno() {
return sno;
}
public void setSno(String sno) {
this.sno = sno;
}
public Double getScore() {
return score;
}
public void setScore(Double score) {
this.score = score;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "StudentVO{" +
"id=" + id +
", name='" + name + '\'' +
", sno='" + sno + '\'' +
", score=" + score +
", sex='" + sex + '\'' +
", hobby='" + hobby + '\'' +
", age=" + age +
'}';
}
}
StudentDO.java
public class StudentDO {
private Integer id;
private String name;
private String sno;
private Double score;
private String sex;
private String hobby;
private Integer age;
public StudentDO() {
}
public StudentDO(Integer id, String name, String sno, Double score, String sex, String hobby, Integer age) {
this.id = id;
this.name = name;
this.sno = sno;
this.score = score;
this.sex = sex;
this.hobby = hobby;
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSno() {
return sno;
}
public void setSno(String sno) {
this.sno = sno;
}
public Double getScore() {
return score;
}
public void setScore(Double score) {
this.score = score;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "StudentDO{" +
"id=" + id +
", name='" + name + '\'' +
", sno='" + sno + '\'' +
", score=" + score +
", sex='" + sex + '\'' +
", hobby='" + hobby + '\'' +
", age=" + age +
'}';
}
}