| 为什么要使用clone为什么要使用clone,直接new一个对象不就好了吗,实际使用中,直接new一个对象也不好,解决不了"新数据"会影响原始数据的问题。这里简单创建了一个测试对象WhyClone。
 public class WhyClone {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
 然后创建两个WhyClone 对象,并且使用一个对另一个赋值,赋值之后修改被赋值的内容。     
    static void whyClone(){
        WhyClone wc1 = new WhyClone();
        wc1.setName("wc1");
        WhyClone wc2 = new WhyClone();
        wc2 = wc1;
        
        System.out.println(wc1);
        System.out.println(wc2);
        
        System.out.println(wc1.getName());
        System.out.println(wc2.getName());
        
        wc2.setName("wc2");
        
        System.out.println(wc1);
        System.out.println(wc2);
        
        System.out.println(wc1.getName());
        System.out.println(wc2.getName());
    }
 编译结果: clone.WhyClone@7a07c5b4
clone.WhyClone@7a07c5b4
wc1
wc1
clone.WhyClone@7a07c5b4
clone.WhyClone@7a07c5b4
wc2
wc2
 
 查看结果发现:wc2被wc1赋值后,wc1和wc2指向同一块地址clone.WhyClone@7a07c5b4,且内容相同,且给wc2赋值字符串”wc2“后,wc1的内容也变成”wc2“。通常开发者需要改变wc2的值且不影响wc1,这就是为什么要使用clone的原因。 clone分为浅拷贝和深拷贝。浅拷贝拷贝时,拷贝对象需要实现Cloneable接口,并重写clone() 。 public class ShallowClone implements Cloneable{
    private String name;
    private Inner inner;
    
    public Inner getInner() {
        return inner;
    }
    public void setInner(Inner inner) {
        this.inner = inner;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    public static class Inner{
        public Inner(String tag) {
            this.tag = tag;
        }
        public String  tag;
    }
}
 测试代码:     
    static void shallowClone() throws CloneNotSupportedException {
        ShallowClone sc1 = new ShallowClone();
        sc1.setInner(new ShallowClone.Inner("inner"));
        sc1.setName("sc1");
        ShallowClone sc2 = (ShallowClone) sc1.clone();
        
        System.out.println(sc1);
        System.out.println(sc2);
        System.out.println(sc1.getInner());
        System.out.println(sc2.getInner());
        
        System.out.println(sc1.getName());
        System.out.println(sc2.getName());
        System.out.println(sc1.getInner().tag);
        System.out.println(sc2.getInner().tag);
        
        System.out.println(sc1.getName() == sc2.getName());
        
        sc2.setName("sc2");
        sc2.getInner().tag = "outer";
        
        System.out.println(sc1);
        System.out.println(sc2);
        System.out.println(sc1.getInner());
        System.out.println(sc2.getInner());
        
        System.out.println(sc1.getName());
        System.out.println(sc2.getName());
        System.out.println(sc1.getInner().tag);
        System.out.println(sc2.getInner().tag);
    }
 编译结果:
  
  比较编译结果发现:直接修改name属性,sc1和sc2并不互相影响,但是两者的Inner指向的是同一个,修改sc2对象Inner的tag属性后,sc1也被修改了,说明ShallowClone.Inner用的同一个,想要一刀两断又没有彻底了断,属于藕断丝连的情况,也就是clone不彻底,称之为浅拷贝。
 深拷贝深拷贝顾名思义就是除了是同一类型的外,所有属性都没有联系,新对象是一块完全独立的内存,两者之间没有任何影响。 public class DeepCloneOuter implements Cloneable{
    public DeepCloneInner deepCloneInner;
    @Override
    public Object clone() throws CloneNotSupportedException {
        DeepCloneOuter deepCloneOuter = (DeepCloneOuter) super.clone();
        deepCloneOuter.deepCloneInner = (DeepCloneInner) deepCloneInner.clone();
        return deepCloneOuter;
    }
}
 public class DeepCloneInner implements Cloneable, Serializable {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
 测试代码:     
    static void deepClone() {
        System.out.println("*****************************");
        DeepCloneOuter deepCloneOuter = new DeepCloneOuter();
        deepCloneOuter.deepCloneInner = new DeepCloneInner();
        deepCloneOuter.deepCloneInner.setName("source");
        try {
            DeepCloneOuter deepCloneOuter2 = (DeepCloneOuter) deepCloneOuter.clone();
            System.out.println(deepCloneOuter);
            System.out.println(deepCloneOuter2);
            System.out.println(deepCloneOuter.deepCloneInner.getName());
            System.out.println(deepCloneOuter2.deepCloneInner.getName());
            System.out.println(deepCloneOuter.deepCloneInner.getName() == deepCloneOuter2.deepCloneInner.getName());
            System.out.println(deepCloneOuter.deepCloneInner == deepCloneOuter2.deepCloneInner);
            
            deepCloneOuter2.deepCloneInner.setName("clone");
            System.out.println(deepCloneOuter);
            System.out.println(deepCloneOuter2);
            System.out.println(deepCloneOuter.deepCloneInner.getName());
            System.out.println(deepCloneOuter2.deepCloneInner.getName());
            System.out.println(deepCloneOuter.deepCloneInner.getName() == deepCloneOuter2.deepCloneInner.getName());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
 编译结果: clone.DeepCloneOuter@68de145
clone.DeepCloneOuter@27fa135a
source
source
true
false
clone.DeepCloneOuter@68de145
clone.DeepCloneOuter@27fa135a
source
clone
false
false
  编译结果说明深拷贝拷中的对象除了长得像,初此之外没有任何联系。当拷贝对象比较复杂的时候,该拷贝方法需要单独拷贝很多东西,所以不常用,利用序列化拷贝对象较为常用。
 序列化深拷贝序列化深拷贝是通过序列化对象,之后反序列化,利用字节流写入被拷贝对象并读取后得到新对象,相当于用户参照被拷贝对象手动开辟了一块新内存供新对象使用。需要拷贝的对象只要实现Serializable即可。
 public class SerializationClone implements Serializable {
    private String name;
    private Inner inner;
    public Inner getInner() {
        return inner;
    }
    public void setInner(Inner inner) {
        this.inner = inner;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public static class Inner implements Serializable{
        private String tag;
        public String getTag() {
            return tag;
        }
        public void setTag(String tag) {
            this.tag = tag;
        }
    }
}```
拷贝工具:
```java
public class CloneUtil {
    public static <T extends Serializable> T clone(T objection){
        T cloneObjection = null;
        try {
            
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ObjectOutputStream obs = new ObjectOutputStream(out);
            
            obs.writeObject(objection);
            
            obs.close();
            
            ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(ios);
            
            cloneObjection = (T) ois.readObject();
            
            ois.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return cloneObjection;
    }
}
 测试代码:     
    static void serializationClone(){
        SerializationClone serializationClone = new SerializationClone();
        serializationClone.setName("serializationClone");
        SerializationClone.Inner inner = new SerializationClone.Inner();
        inner.setTag("serializationCloneTag");
        serializationClone.setInner(inner);
        
        System.out.println("**************原数据**********");
        System.out.println(serializationClone);
        System.out.println(serializationClone.getInner());
        System.out.println(serializationClone.getName());
        System.out.println(serializationClone.getInner().getTag());
        
        SerializationClone serializationClone1 = CloneUtil.clone(serializationClone);
        System.out.println("**************拷贝后**********");
        System.out.println(serializationClone1);
        System.out.println(serializationClone1.getInner());
        System.out.println(serializationClone1.getName());
        System.out.println(serializationClone1.getInner().getTag());
        
        serializationClone1.setName("serializationClone1");
        serializationClone1.getInner().setTag("serializationClone1Tag1");
        
        System.out.println("**************修改后原数据**********");
        System.out.println(serializationClone);
        System.out.println(serializationClone.getInner());
        System.out.println(serializationClone.getName());
        System.out.println(serializationClone.getInner().getTag());
        
        System.out.println("**************修改后拷贝数据**********");
        System.out.println(serializationClone1);
        System.out.println(serializationClone1.getInner());
        System.out.println(serializationClone1.getName());
        System.out.println(serializationClone1.getInner().getTag());
    }
 编译结果: **************原数据**********
clone.SerializationClone@26a1ab54
clone.SerializationClone$Inner@3d646c37
serializationClone
serializationCloneTag
**************拷贝后**********
clone.SerializationClone@156643d4
clone.SerializationClone$Inner@123a439b
serializationClone
serializationCloneTag
**************修改后原数据**********
clone.SerializationClone@26a1ab54
clone.SerializationClone$Inner@3d646c37
serializationClone
serializationCloneTag
**************修改后拷贝数据**********
clone.SerializationClone@156643d4
clone.SerializationClone$Inner@123a439b
serializationClone1
serializationClone1Tag1
 比较拷贝前后的对象发现两者地址都不一样,包括内部对象的地址,修改任何属性也不会相互影响。 深拷贝建议使用序列化深拷贝 |