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

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

首先有2个类如下

 /**
* Created by yesiming on 16-11-19.
*/
public class Car {
private String name;
private String color;
// 省略set/get
}
}
 /**
* Created by yesiming on 16-11-20.
*/
public class Kia extends Car{
private String model;
// 省略set/get
}

我们先操作入职Kia的域

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

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

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

 /**
* 输出所有域,包括父类中的域(通过递归实现)
*/
public void showAllField(Class clazz) {
Field[] fields = clazz.getDeclaredFields();
System.out.println("------" + clazz.toString() + "------");
if(fields != null && fields.length > 0) {
for(Field field : fields) {
System.out.println(field);
}
}
Class superClazz = clazz.getSuperclass();
if(superClazz != Object.class) { // 结束递归
showAllField(superClazz); // 递归
}
} @Test
public void showAllFieldTest() {
Class clazz = Kia.class;
showAllField(clazz);
}

运行结果如下:

------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

 /**
* 通过专业操作JavaBean的内省,Introspector复制有继承的类
* @throws Exception
*/
@Test
public void showProfile() throws Exception { Kia k1 = new Kia(); // 源对象,继承自Car
k1.setName("起亚"); // 这是Car中的域
k1.setColor("白色"); // 这是Car中的域
k1.setModel("K4");
Kia k2 = new Kia(); // 目标对象 BeanInfo beanInfo = Introspector.getBeanInfo(Kia.class); // 得到Kia的Bean信息
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors(); //通过BeanInfo得到域的描述符
for (PropertyDescriptor pd : pds) {
if (pd.getName() == "getClass()") {
continue;
}
if (pd.getReadMethod() == null || pd.getWriteMethod() == null) { // 如果set, get不配对就不复制
continue;
}
// 反射set目标对象中的域
pd.getWriteMethod().invoke(k2, pd.getReadMethod().invoke(k1));
}
System.out.println(k2.getName() + k2.getModel() + k2.getColor());
}

Java反射 - 2(对象复制,父类域,内省)的更多相关文章

  1. Java 反射 Class对象

    Java 反射 Class对象 @author ixenos 关键字:RTTI.动态绑定.动态加载.获得Class引用.泛型Class引用.newInstance的坑.JVM中的泛型类型信息 RTTI ...

  2. 【译】2. Java反射——Class对象

    原文地址:http://tutorials.jenkov.com/java-reflection/classes.html ====================================== ...

  3. Java反射获取对象成员属性,getFields()与getDeclaredFields()方法的区别

    Java反射获取对象成员属性,getFields()与getDeclaredFields()方法的区别 ​ 在工作中遇到一个问题,就是你需要去判断某个字符串是不是对象的某个成员属性名,然后根据判断结果 ...

  4. java 反射,注解,泛型,内省(高级知识点)

     Java反射 1.Java反射是Java被视为动态(或准动态)语言的一个关键性质.这个机制允许程序在运行时透过Reflection APIs    取得任何一个已知名称的class的内部信息, 包括 ...

  5. java反射构建对象和方法的反射调用

    Java反射技术应用广泛,其能够配置:类的全限定名,方法和参数,完成对象的初始化,设置是反射某些方法.可以增强java的可配置性. 1.1 通过反射构建对象(无参数): 例如我们使用 ReflectS ...

  6. Java反射获取对象VO的属性值(通过Getter方法)

    有时候,需要动态获取对象的属性值. 比如,给你一个List,要你遍历这个List的对象的属性,而这个List里的对象并不固定.比如,这次User,下次可能是Company. e.g. 这次我需要做一个 ...

  7. 第五课 JAVA反射获取对象属性和方法(通过配置文件)

    Service1.java package reflection; public class Service1 { public void doService1(){ System.out.print ...

  8. 用Java反射输出对象的所有属性的值

    获取对象的类类型 Class cls = obj.getClass(); 用类类型获取属性数组 getFields()获取的是共有属性 getDeclaredFields()可以获取所有属性 Fiel ...

  9. 第五课 JAVA反射获取对象属性和方法

    package com.hero; import java.lang.reflect.Field; public class TestReflction5 { public static void m ...

随机推荐

  1. codeforces 235 B. Let's Play Osu!

    You're playing a game called Osu! Here's a simplified version of it. There are n clicks in a game. F ...

  2. Nginx 基本配置和日志分析

    最近在维护的一个项目,路由转发规则都统一通过Nginx转发,所以再次参考部分博文和书本,熟悉Nginx的基本配置,还有一个重点也是日志的分析 Nginx 常用模块是server块,location块. ...

  3. yo angualr-fullstatck 项目打包部署

    yoeman使用grunt进行打包部署,直接运行grunt命令即可,期间会对代码进行检查,如果存在不规范的地方jshint会指定出来. grunt会对静态资源进行打包而且对资源文件名进行了MD5作为版 ...

  4. poj 1573Robot Motion

    http://poj.org/problem?id=1573 #include<cstdio> #include<cstring> #include<algorithm& ...

  5. Asteroids

    http://poj.org/problem?id=3041 #include<cstdio> #include<cstring> #include<algorithm& ...

  6. [EXCEL] 在单元格中自动输入时间和日期

    选中需输入的单元格,直接按下“Ctrl+:”组合键可输入当前日期:如果直接按下“Ctrl+Shift+:”组合键即可输入当前时间:当然也可以在单元格中先输入其他文字然后再按以上组合键,如先输入“当前时 ...

  7. Windows系统编程之进程间通信

    Windows系统编程之进程间通信作者:北极星2003来源:看雪论坛(www.pediy.com)Windows 的IPC(进程间通信)机制主要是异步管道和命名管道.(至于其他的IPC方式,例如内存映 ...

  8. 【HDOJ】1313 Round and Round We Go

    大数乘,果断java A了. import java.util.Scanner; import java.lang.StringBuilder; import java.math.BigInteger ...

  9. COJ 1011 WZJ的数据结构(十一)树上k大

    题解:主席树&DFS序. PS:为什么我一开始Wa了N发 是因为有一个左区间我写成[L,M+1]了.......................... #include<iostream ...

  10. SparkContext自定义扩展textFiles,支持从多个目录中输入文本文件

    需求   SparkContext自定义扩展textFiles,支持从多个目录中输入文本文件   扩展   class SparkContext(pyspark.SparkContext): def ...