Java反射 - 2(对象复制,父类域,内省)

为什么要复制对象?假设有个类Car,包含name,color2个属性,那么将car1对象复制给car2对象,只需要car2.setName(car1.getName)与car2.setColor(car1.getColor)两部操作即可。

实际项目中有很多类都有超过几十个,甚至上百个字段,这时如果采用以上方式,将会有很大的代码工作量与重复劳动。解决方法是使用反射机制。

首先有2个类如下

1 /**
2  * Created by yesiming on 16-11-19.
3  */
4 public class Car {
5     private String name;
6     private String color;
7     // 省略set/get
8     }
9 }
1 /**
2  * Created by yesiming on 16-11-20.
3  */
4 public class Kia extends Car{
5     private String model;
6     // 省略set/get
7 }

我们先操作入职Kia的域

 1 /**
 2      * 通过反射进行对象复制(漏洞:不能复制父类中的域)
 3      * @throws Exception
 4      */
 5     @Test
 6     public void copyObject() throws Exception{
 7         User src = new User(); // 源对象
 8         src.setId(1);
 9         src.setName("yesiming");
10         User target = new User(); // 目标对象
11         Class clazz = User.class;
12         Field[] fields = clazz.getDeclaredFields(); // 得到该类声明的域(不包含父类的域)
13         for(Field field : fields) {
14             if(!field.isAccessible())
15                 field.setAccessible(true); // 设置可访问
16             field.set(target, field.get(src)); // 从源对象get值set到目标对象
17         }
18         // 输出显示
19         for(Field field : fields) {
20             System.out.println(field.get(target));
21         }
22     }

由于getDeclaredFields方法不能得到超类中的域,所以上述操作有缺陷,甚至不具有实际意义

下面是如何得到超类中的域,使用递归即可

 1 /**
 2      * 输出所有域,包括父类中的域(通过递归实现)
 3      */
 4     public void showAllField(Class clazz) {
 5         Field[] fields = clazz.getDeclaredFields();
 6         System.out.println("------" + clazz.toString() + "------");
 7         if(fields != null && fields.length > 0) {
 8             for(Field field : fields) {
 9                 System.out.println(field);
10             }
11         }
12         Class superClazz = clazz.getSuperclass();
13         if(superClazz != Object.class) { // 结束递归
14             showAllField(superClazz); // 递归
15         }
16     }
17 
18     @Test
19     public void showAllFieldTest() {
20         Class clazz = Kia.class;
21         showAllField(clazz);
22     }

运行结果如下:

------class o1.o1_a.Kia------
private java.lang.String o1.o1_a.Kia.model
------class o1.o1_a.Car------
private java.lang.String o1.o1_a.Car.name
private java.lang.String o1.o1_a.Car.color

 那么好,结合上述2种操作,就能写出具有实用价值的类复制方法了吗?

当然不是,Java中操作Bean的专业户是内省,Introspector

 1 /**
 2      * 通过专业操作JavaBean的内省,Introspector复制有继承的类
 3      * @throws Exception
 4      */
 5     @Test
 6     public void showProfile() throws Exception {
 7 
 8         Kia k1 = new Kia(); // 源对象,继承自Car
 9         k1.setName("起亚"); // 这是Car中的域
10         k1.setColor("白色"); // 这是Car中的域
11         k1.setModel("K4");
12         Kia k2 = new Kia(); // 目标对象
13 
14         BeanInfo beanInfo = Introspector.getBeanInfo(Kia.class); // 得到Kia的Bean信息
15         PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors(); //通过BeanInfo得到域的描述符
16         for (PropertyDescriptor pd : pds) {
17             if (pd.getName() == "getClass()") {
18                 continue;
19             }
20             if (pd.getReadMethod() == null || pd.getWriteMethod() == null) { // 如果set, get不配对就不复制
21                 continue;
22             }
23             // 反射set目标对象中的域
24             pd.getWriteMethod().invoke(k2, pd.getReadMethod().invoke(k1));
25         }
26         System.out.println(k2.getName() + k2.getModel() + k2.getColor());
27     }

 

posted on 2016-11-20 00:50  iTown  阅读(1254)  评论(0编辑  收藏  举报

导航