黑马程序员技术交流社区

标题: 关于运行时通过反射复制对象 [打印本页]

作者: 黑马刘涛    时间: 2012-8-2 12:54
标题: 关于运行时通过反射复制对象
直接上代码
  1. package com.itcast.test2;
  2. import java.lang.reflect.*;

  3. import com.itcast.test1.Ball;
  4. public class RuntimeClone {

  5.         /**
  6.          * 运行时复制对象
  7.          * 这个方法能够创建一个和参数 object 同样类型的对象,
  8.          * 然后把 object 对象中的所有属性拷贝到新建的对象中,
  9.          * 并将它返回 ,这个例子只能复制简单的 JavaBean
  10.          * @author shandawang
  11.          */
  12.         public static void main(String[] args) {
  13.                 // TODO Auto-generated method stub
  14.                 Ball ball = new Ball("basketball",1);
  15.                 try {
  16.                         Ball cloneBall = (Ball)runtimeClone(ball);
  17.                         System.out.println(cloneBall.toString());
  18.                 } catch(Exception e) {
  19.                         e.printStackTrace();
  20.                 }
  21.         }
  22.         /**
  23.          *
  24.          * @param obj 要复制的对象
  25.          * @param args 构造函数参数列表
  26.          * @return 复制后的对象
  27.          */
  28.         public static Object runtimeClone(Object obj) throws Exception {
  29.                 // 获取对象的完整类型
  30.                 Class<?> classType = obj.getClass();
  31.                 //System.out.println(classType.getName());
  32.                 // 使用默认构造方法创建一个实例
  33.                 /*
  34.                  * 注意:若Ball类型定义了带参数的构造函数,则JVM不会定义默认构造函数
  35.                  * 此时必须自定义不带参数的构造函数
  36.                  */
  37.                 Object cloneObj = classType.getConstructor().newInstance();
  38.                 // 获取被复制对象的所有属性
  39.                 Field[] fields = classType.getDeclaredFields();
  40.                 String[] fieldNames = new String[fields.length]; // 属性名数组
  41.                 for(int i = 0;i < fields.length;i++) {
  42.                         // 获取属性名,通过反射调用对象的getters,setters
  43.                         fields[i].setAccessible(true);
  44.                         fieldNames[i] = fields[i].getName();
  45.                         // 属性名的首字母大写,获取方法名
  46.                         String firstUpperCaseLetter = fieldNames[i].substring(0, 1).toUpperCase();
  47.                         String getterMethodName = "get" + firstUpperCaseLetter +
  48.                                         fieldNames[i].substring(1,fieldNames[i].length()); // get方法名
  49.                         //System.out.println(getterMethodName);
  50.                         String setterMethodName = "set" + firstUpperCaseLetter +
  51.                                         fieldNames[i].substring(1,fieldNames[i].length()); // set方法名
  52.                         //System.out.println(setterMethodName);
  53.                         Method getterMethod = classType.getMethod(getterMethodName);
  54.                         Method setterMethod = classType.getMethod(setterMethodName,fields[i].getType());
  55.                         // 调用原对象的get方法获取指定属性值
  56.                         Object fieldValue = getterMethod.invoke(obj);
  57.                         // 调用复制对象的set方法设定指定属性值
  58.                         setterMethod.invoke(cloneObj,fieldValue);
  59.                 }
  60.                 return cloneObj;
  61.         }
  62. }
复制代码
  1. package com.itcast.test1;

  2. import java.io.Serializable;

  3. /**
  4. * javabean多用于封装属性,而很少具备某些特定的方法功能。
  5. * 试想,javabean的功能就是传递数据,那么类权限为共有也
  6. * 就不足为奇了。下面是标准javabean要遵守的一些规范:
  7. *1. 类访问权限为公有
  8. *2. 所有属性为私有
  9. *3. 每个字段对外提供setter方法和getter方法
  10. *4. 具备一个无参的构造方法
  11. */
  12. public class Ball implements Serializable {
  13.         //private static final long serialVersionUID = 1L;
  14.         /**
  15.          * 实现序列化
  16.          * 要将某类的对象序列化,则该类必须实现Serializable接口,该接口
  17.          * 仅是一个标志,告诉JVM该类的对象可以被序列化。如果某类未实现Serializable接口,
  18.          * 则该类对象不能实现序列化。
  19.          */
  20.         private String ballName;
  21.         private int serialNumber;
  22.         public Ball() {}
  23.         public Ball(String ballName, int serialNumber) {
  24.                 super();
  25.                 this.ballName = ballName;
  26.                 this.serialNumber = serialNumber;
  27.         }
  28.         public String getBallName() {
  29.                 return ballName;
  30.         }
  31.         public void setBallName(String ballName) {
  32.                 this.ballName = ballName;
  33.         }
  34.         public int getSerialNumber() {
  35.                 return serialNumber;
  36.         }
  37.         public void setSerialNumber(int serialNumber) {
  38.                 this.serialNumber = serialNumber;
  39.         }
  40.         @Override
  41.         public String toString() {
  42.                 return "Ball [ballName=" + ballName + ", serialNumber=" + serialNumber
  43.                                 + "]";
  44.         }        
  45. }
复制代码
Ball类是之前序列化和反序列化时实现了serializable接口。现在我要运行时通过反射复制对象,而ball对象里有序列化ID号,获取属性时同时也会获得这个属性。而这不是我希望的(程序不能运行)。当所有属性都是private时,能不能跳过这个序列号属性。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2