zoukankan      html  css  js  c++  java
  • 反射实现java深度克隆

    、克隆
      

    有时想得到对象的一个复制品,该复制品的实体是原对象实体的克隆。复制品实体的变化不会引起原对象实体发生变化,这样的复制品称为原对象实体的克隆对象或简称克隆。

      

    1、浅复制(浅克隆)

      

    概念:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。

      

    方法:类implements Cloneable,然后重写clone()方法,在clone()方法中调用super.clone()即可,没有其他操作了

      

    2、深复制(深克隆)

      

    概念:被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。

     一、克隆的实现

    1、通过java的序列化实现克隆,即先对原对象进行序列化,然后再反序列化得到目标对象。

    2. 通过反射进行,通过反射,获取对象的内部数据域,然后将数据依次复制,不多说,先上代码

     package Reflection;

     

    import java.lang.reflect.Array;

    import java.lang.reflect.Field;

    import java.lang.reflect.Modifier;

    import java.util.ArrayList;

    import java.util.HashMap;

    import java.util.List;

    import java.util.Map;

     

    public class DeepCloneUtil {

    public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, InstantiationException {

    Person p = new Person("zhanchi",26);

    System.out.println(Person.num);

    Person p2 = (Person) cloneObject(p);

    System.out.println(p2.getName());

    System.out.println(p2.getAge());

    System.out.println(p.list == p2.list);

    System.out.println(p2.list.get(0) == p2);

    System.out.println(p.list.get(0) == p2);

    System.out.println(Person.num);

    }

    private static List<Field> getAllFieads(Object o) {

     

    List<Field> fields = new ArrayList<Field>();

     

    if (null == o)

    return fields;

     

    Class<?> type = o.getClass();

    do {

    for (Field f : type.getDeclaredFields()) {

    fields.add(f);

    }

    type = type.getSuperclass();

    } while (null != type);

     

    return fields;

     

    }

     

    public static boolean isSimpleObject(Object o) {

    Class<?> type = o.getClass();

    if (type.isPrimitive()) { // 基本类型

    return true;

    }

     

    // 不可更改的变量类型 如 String,Long

    if (type.equals(String.class))

    return true;

    if (type.equals(Long.class))

    return true;

    if(type.equals(Boolean.class))

    return true;

    if(type.equals(Short.class))

    return true;

    if(type.equals(Integer.class))

    return true;

    if(type.equals(Character.class))

    return true;

    if(type.equals(Float.class))

    return true;

    if(type.equals(Double.class))

    return true;

    if(type.equals(Byte.class))

    return true;

     

    return false;

    }

     

    public static Object cloneObject(Object o) throws IllegalArgumentException, IllegalAccessException, InstantiationException{

    if(null == o)

    return null;

    // 使用Map保存原对象和副本对象之间的结构,防止被多次引用的对象重复重建

    Map<Object,Object> map = new HashMap<Object,Object>();

    return cloneObject(o,map);

    }

    private static Object cloneObject(Object o, Map<Object, Object> map)

    throws IllegalArgumentException, IllegalAccessException,

    InstantiationException {

    if (null == o)

    return null;

    Object newInstance = null;

     

    newInstance = map.get(o);

    if (null != newInstance) {

    return newInstance;

    }

    if(isSimpleObject(o))

    return o;

    // 数组类型

    if(o.getClass().isArray()){

    return cloneArray(o,map);

    }

     

    Class<?> type = o.getClass();

    newInstance = type.newInstance();

    map.put(o, newInstance);

     

    cloneFields(o, newInstance, map);

     

    return newInstance;

    }

    private static Object cloneArray(Object o,Map<Object, Object> map) throws IllegalArgumentException, IllegalAccessException, InstantiationException{

    if(null == o)

    return null;

    if(!o.getClass().isArray()){

    return cloneObject(o,map);

    }

    int len = Array.getLength(o);

    Object array = Array.newInstance(o.getClass().getComponentType(), len);

    map.put(o, array);

    for(int i = 0; i < len; i++){

    Array.set(array, i, cloneObject(Array.get(o, i),map));

    }

    return array;

    }

    private static void cloneFinalObject(Object object, Object newObject, Map<Object, Object> map)throws IllegalArgumentException, IllegalAccessException, InstantiationException{

    if(object == null || newObject == null || object == newObject  || !newObject.getClass().equals(newObject.getClass()))

    return ;

    // 对于final类型的变量

    if(null != map.get(newObject)){

    return;

    }

    map.put(newObject, newObject);

    cloneFields(object, newObject, map);

    return ;

    }

     

     

    private static void cloneFields(Object object, Object newObject,

    Map<Object, Object> map) throws SecurityException,

    IllegalArgumentException, IllegalAccessException,

    InstantiationException {

    if(null == object || null == newObject){

    return ;

    }

    List<Field> fields = getAllFieads(object);

     

    for (Field f : fields) {

    // 静态变量过滤掉 或者final的变量

    if(Modifier.isStatic(f.getModifiers()))

    continue;

    // 常量

    if(Modifier.isFinal(f.getModifiers())){

    cloneFinalObject(f.get(object),f.get(newObject),map);

    }else{

    f.setAccessible(true);

    f.set(newObject, cloneObject(f.get(object), map));

    }

    }

    }

    }

     

    class Person{

    static int num = 0;

    Person p;

    final List<Person> list = new ArrayList<Person>();

        

    String [] testString = new String[3];

        public Person() {

             num ++ ;

        }

       

        public Person(String name, int age) {

            this.age=age;

            this.name=name;

            p = this;

            testString[2] = name;

            list.add(p);

            list.add(new Person());

            num ++ ;

        }

        public String getName() {

            return name;

        }

        public int getAge() {

            return age;

        }

        @Override

        public String toString(){

            return "["+this.name+"  "+this.age+"]";

        }

        private String name;

        private int age;

    }

  • 相关阅读:
    配置动态刷新RefreshScope注解使用局限性(一)
    OAuth2 Token 一定要放在请求头中吗?
    Spring Boot 2.3 新特配置文件属性跟踪
    为什么 Spring Boot 2.3.0 放弃Maven最终拥抱Gradle
    Spring Boot 2.3.0 新特性Redis 拓扑动态感应
    【spring cloud hoxton】Ribbon 真的能被 spring-cloud-loadbalancer 替代吗
    Spring Cloud Gateway 扩展支持动态限流
    聊聊 OAuth 2.0 的 token expire_in 使用
    「starter推荐」简单高效Excel 导出工具
    用mint-ui tabber写餐厅分层
  • 原文地址:https://www.cnblogs.com/KingIceMou/p/7169696.html
Copyright © 2011-2022 走看看