Clone的理解

首先看张表了解一下分类以及区别:

类型 共同点 区别 什么情况下是所谓的类型
深度克隆

一个新的对象实例的所有

变量都含有与原来的对象

相同的值,对于基本类型

复制一份新产生的对象

非基本类型指向被复制的

新对象

若某个对象的属性都为基础类型,则

它的clone为深度克隆

浅度克隆

非基本类型指向原对象,只

是一个引用

集合的默认clone或Add以及AddAll

集合的构造方法

System.arraycopy()

要注意String的克隆是一个特例,首先要知道String克隆是一个浅度克隆,但是又因为String的特殊性,在克隆时会有两个String类型的引用,所以如果改变克隆得到的对象的值是不会改变被克隆的对象的值的(这里我们可以假定为深度克隆)

但是StringBuffer以及StringBuilder就不能够这么认为了,如果想要实现这两个类型的深度克隆,我们必须在类的clone方法中进行主动拷贝操作

一段代码来加强记忆:

public class TestClone {
    public static void main(String[] args){
        ArrayList<InfoBean> lists=new ArrayList<>();
        
        lists.add(new InfoBean("zyf", 23));
        lists.add(new InfoBean("pyh", 18));
        lists.add(new InfoBean("zxh", 23));

        for(InfoBean ib:lists){
            System.out.println(ib);
        }
//        浅度克隆
        ArrayList<InfoBean> lists2=(ArrayList<InfoBean>)lists.clone();
//        深度克隆
        ArrayList<InfoBean> lists3=new ArrayList<>();
        for(int i=0;i<lists.size();i++){
            try {
                lists3.add((InfoBean)lists.get(i).clone());
            } catch (CloneNotSupportedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
//        对list2浅度克隆的验证
        lists2.get(1).name="hhhhh";
        System.out.println("对list2浅度克隆的验证-----------------------------");
        for(InfoBean ib:lists){
            System.out.println(ib);
        }
//        对list3深度克隆的验证
        lists3.get(1).name="zzzzzz";
        System.out.println("对list3浅度克隆的验证-----------------------------");
        for(InfoBean ib:lists){
            System.out.println(ib);
        }
        
    }
}
class InfoBean implements Cloneable{
    public String name;
    public int age;
    
    public InfoBean(String name,int age){
        this.name=name;
        this.age=age;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    @Override
    public String toString() {
        return "InfoBean [name=" + name + ", age=" + age + "]";
    }
    
}

看一下输出结果:

从输出结果可以说明一切了吧!

接下来说一下实现克隆的3种基本方法:

1 通过实现Cloneable接口并重写Object的clone方法实现浅度克隆
2 通过实现Cloneable接口并重写Object的clone方法实现深度克隆
3 通过对象的序列化和反序列化实现深度克隆

第一种:

class InfoBean implements Cloneable{
    public String name;
    public int age;
    
    public InfoBean(String name,int age){
        this.name=name;
        this.age=age;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    @Override
    public String toString() {
        return "InfoBean [name=" + name + ", age=" + age + "]";
    }
    
}

第二种:

class InfoBean implements Cloneable{
    public String name;
    public int age;
    
    public InfoBean(String name,int age){
        this.name=name;
        this.age=age;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    @Override
    public String toString() {
        return "InfoBean [name=" + name + ", age=" + age + "]";
    }
    
}
class InfoBean2 implements Cloneable{
    public String name;
    public int age;
    public InfoBean bean;
    
    public InfoBean2(String name,int age){
        this.name=name;
        this.age=age;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        InfoBean2 ib2=(InfoBean2)super.clone();
        ib2.bean=(InfoBean)bean.clone(); //这里的第二个bean是由上一句克隆过来的,是成员变量
        return ib2;
    }
    @Override
    public String toString() {
        return "InfoBean2 [name=" + name + ", age=" + age + ", bean=" + bean
                + "]";
    }
    
}

第三种:

class CloneUtil{
    public static<T extends Serializable>T clone(T obj){
        T cloneObj =null;
        try{
            ByteArrayOutputStream byteOut=new ByteArrayOutputStream();
            ObjectOutputStream objOut =new ObjectOutputStream(byteOut);
            objOut.writeObject(obj);
            objOut.close();
            ByteArrayInputStream byteIn =new ByteArrayInputStream(byteOut.toByteArray());
            ObjectInputStream objIn =new ObjectInputStream(byteIn);
            cloneObj =(T)objIn.readObject();
            objIn.close();
        }catch(IOException e){
            e.printStackTrace();
        }catch(ClassNotFoundException e){
            e.printStackTrace();
        }
        return cloneObj;
    }
}

 

posted @ 2018-05-04 19:57  醉醉龙  阅读(318)  评论(0编辑  收藏  举报