zoukankan      html  css  js  c++  java
  • 再谈java clone 以及 浅/深拷贝

    简单对象的拷贝,直接使用其clone方法 即可, 不会有什么问题:

    class Dog implements Cloneable 
    
    public Dog clone() {
    
    int age;
    String name;
    
    // getter setter
    
    
    Dog myDog = null;
    try {
      myDog = (Dog) super.clone();
    } catch (CloneNotSupportedException e) {
      e.printStackTrace();
    }
      return myDog;
    }

    // any test ...

    如此简单!

    不过,如果对象有嵌套,我们还是使用这个做法(浅拷贝), 不注意就会出问题:

    package design.creator.prototype;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 浅拷贝:
     */
    class Dog implements Cloneable {
        int age;
        String name;
        List list;
        Pojo pojo;
    
        public Dog(String tempName) {
            name = tempName;
            list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
            pojo = new Pojo();
            pojo.setV1(111);
            pojo.setV2("aa");
        }
    
    //    public void ShowName() {
    //        System.out.println(name);
    //    }
    
        public Dog clone() {
            Dog myDog = null;
            try {
                myDog = (Dog) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return myDog;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        
    
        public String getName() {
            return name;
        }
    
        public List getList() {
            return list;
        }
    
        public void setList(List list) {
            this.list = list;
        }
    
        @Override
        public String toString() {
            return "Dog [age=" + age + ", name=" + name + 
                    ", list=" + list + "]" + ", pojo=" + pojo + "]";
        }
    
        public Pojo getPojo() {
            return pojo;
        }
    
        public void setPojo(Pojo pojo) {
            pojo = pojo;
        }
        
    }
    
    class Pojo {
        int v1;
        String v2;
        public int getV1() {
            return v1;
        }
        public void setV1(int v1) {
            this.v1 = v1;
        }
        public String getV2() {
            return v2;
        }
        public void setV2(String v2) {
            this.v2 = v2;
        }
        @Override
        public String toString() {
            return "Pojo [v1=" + v1 + ", v2=" + v2 + "]";
        }
        
        
    }
    
    public class PrototypeTest {
        public static void main(String[] args) {
            Dog myDog = new Dog("热狗");
            myDog.setAge(12);
            Dog newDog = (Dog) myDog.clone();
            
            System.out.println(" myDog " + myDog );
            System.out.println(" newDog " + newDog );
            
    //        myDog.ShowName();
    //        newDog.ShowName();
    
            myDog.setName("aaaaa");
            myDog.setAge(33);
            myDog.getList().clear();
            myDog.getPojo().setV1(222);
            myDog.getPojo().setV2("bbb");
    
    //        myDog.ShowName();
    //        newDog.ShowName();
            
            
            System.out.println(" myDog " + myDog );
            System.out.println(" newDog " + newDog );
        }
    }

    打印

     myDog Dog [age=12, name=热狗, list=[1, 2, 3]], pojo=Pojo [v1=111, v2=aa]]
     newDog Dog [age=12, name=热狗, list=[1, 2, 3]], pojo=Pojo [v1=111, v2=aa]]
     myDog Dog [age=33, name=aaaaa, list=[]], pojo=Pojo [v1=222, v2=bbb]]
     newDog Dog [age=12, name=热狗, list=[]], pojo=Pojo [v1=222, v2=bbb]]

    你可能不懂为什么newDog 的name没变化,而newDog 的pojo、list都发生了变化—— 原来java 的clone 方法把 String当做了普通字段并进行了深复制, 而其他对象类型数据仍然的浅复制。

    那么正确的做法是:

    package design.creator.prototype;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 深度拷贝:
     */
    class Dog implements Cloneable {
        int age;
        String name;
        List list;
        Pojo pojo;
    
        public Dog(String tempName) {
            name = tempName;
            list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
            pojo = new Pojo();
            pojo.setV1(111);
            pojo.setV2("aa");
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        
    
        public String getName() {
            return name;
        }
    
        public List getList() {
            return list;
        }
    
        public void setList(List list) {
            this.list = list;
        }
    
        @Override
        public String toString() {
            return "Dog [age=" + age + ", name=" + name + 
                    ", list=" + list + "]" + ", pojo=" + pojo + "]";
        }
    
        public Pojo getPojo() {
            return pojo;
        }
    
        public void setPojo(Pojo pojo) {
            pojo = pojo;
        }
    
    
        public Dog clone() {
            Dog myDog = null;
            try {
                myDog = (Dog) super.clone();
                myDog.list = (List) ((ArrayList)myDog.list).clone();
                
                // 想要调用其clone方法,必须1 implements Cloneable 2 对其重写clone
                myDog.pojo = (Pojo) myDog.pojo.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return myDog;
        }
    }
    
    class Pojo implements Cloneable{
        int v1;
        String v2;
        public int getV1() {
            return v1;
        }
        public void setV1(int v1) {
            this.v1 = v1;
        }
        public String getV2() {
            return v2;
        }
        public void setV2(String v2) {
            this.v2 = v2;
        }
        @Override
        public String toString() {
            return "Pojo [v1=" + v1 + ", v2=" + v2 + "]";
        }
        
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
        
    }
    
    public class PrototypeTest {
        public static void main(String[] args) {
            Dog myDog = new Dog("热狗");
            myDog.setAge(12);
            Dog newDog = (Dog) myDog.clone();
            
            System.out.println(" myDog " + myDog );
            System.out.println(" newDog " + newDog );
            
    //        myDog.ShowName();
    //        newDog.ShowName();
    
            myDog.setName("aaaaa");
            myDog.setAge(33);
            myDog.getList().clear();
            myDog.getPojo().setV1(222);
            myDog.getPojo().setV2("bbb");
    
    //        myDog.ShowName();
    //        newDog.ShowName();
            
            
            System.out.println(" myDog " + myDog );
            System.out.println(" newDog " + newDog );
        }
    }

    总结:

     clone 方法只是浅拷贝,也就是说他只对象的第一层属性进行拷贝,其对象中的对象是不会进行重新拷贝的, 而仅仅只是拷贝那个引用。 如果对象有嵌套,那么需要注意重写相关步骤,使用 深拷贝。

    参考: 

    http://blog.csdn.net/jariwsz/article/details/8588570

    http://blog.csdn.net/xiaofengcanyuexj/article/details/23212189

  • 相关阅读:
    js中replace的正则替换
    ios沙盒路径
    Android开源框架
    小知识点
    __NSCFConstantString && __NSPlaceholderDictionary
    iq 格式分析
    C 函数
    Xcode报错
    XMPP Server
    H5网站借鉴
  • 原文地址:https://www.cnblogs.com/FlyAway2013/p/3872990.html
Copyright © 2011-2022 走看看