Java数据结构源码分析-前言

1.Cloneable和Serializable

从声明中有两点是需要说明的,其也存在与其他的集合结构中Cloneable和Serializable

public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable {}

1.1 Cloneabale

从下面片段可以看到Cloneable接口并没有任何的方法,其是一个标志性接口,只有实现该接口的类才能调用clone()方法来复制堆上的对象而不是引用.

public interface Cloneable {}

public class CloneBean implements Cloneable {
    private String name;

    public CloneBean(String name){
        this.name=name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        CloneBean fromCloneBean=new CloneBean("OldCloneBean");
        CloneBean toCloneBean=(CloneBean)fromCloneBean.clone();
        toCloneBean.setName("newCloneBean");
        System.out.println(fromCloneBean.name + " vs " + toCloneBean.name);

        CloneBean sameCloneBean=fromCloneBean;
        sameCloneBean.setName("SameCloneBean");
        System.out.println(fromCloneBean.name + " vs " + sameCloneBean.name);
    }
}

//输入结果:
//OldCloneBean vs newCloneBean
//SameCloneBean vs SameCloneBean

package com.job.search.blog.code;

/**
 * Created by wenyi on 16/6/3.
 * Email:caowenyi@meituan.com
 */
public class CloneBean {
    private String name;

    public CloneBean(String name){
        this.name=name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        CloneBean fromCloneBean=new CloneBean("OldCloneBean");
        CloneBean toCloneBean=(CloneBean)fromCloneBean.clone();
        toCloneBean.setName("newCloneBean");
        System.out.println(fromCloneBean.name + " vs " + toCloneBean.name);
    }
}
//输入结果:Exception in thread "main" java.lang.CloneNotSupportedException: com.job.search.blog.code.CloneBean

Java中对象保存于堆上,而引用保存于栈中,因此CloneBean sameCloneBean=fromCloneBean是两个不同名字的引用作用于同一个对象上,因此任意一个引用更改对象都要影响另外一个。为了真正的产生两个对象就需要使用继承于Object的clone()方法。从实验二可以看出如果不在类上生命其是Cloneable的,在调用clone()方法时会产生异常。
另外上面的只是一种浅拷贝,其并不会拷贝对象的field中的对象,而是引用间的赋值。从下面的实验一可以看出CloneBean中的UserBean还是在copy引用,对任意CloneBean中的UserBean的操作都会影响两个CloneBean.
深层次的拷贝,除了要拷贝对象本身还要拷贝对象域中的每个一个对象

public class CloneBean implements Cloneable {
    private String name;
    private UserBean userBean;

    public CloneBean(String name, UserBean userBean) {
        this.name = name;
        this.userBean = userBean;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        String name = "CloneBeanName";
        UserBean userBean = new UserBean("OldUserBean");
        CloneBean fromCloneBean = new CloneBean(name, userBean);
        CloneBean toCloneBean = (CloneBean) fromCloneBean.clone();
        toCloneBean.name="NewBeanName";
        userBean.setName("NewUserBean");
        System.out.println(fromCloneBean.name + "_" + fromCloneBean.userBean + " vs " + toCloneBean.name + "_" + toCloneBean.userBean);
    }
}

//输入结果:CloneBeanName_NewUserBean vs NewBeanName_NewUserBean

package com.job.search.blog.code;

/**
 * Created by wenyi on 16/6/3.
 * Email:caowenyi@meituan.com
 */
public class CloneBean implements Cloneable {
    private String name;
    private UserBean userBean;

    public CloneBean(String name, UserBean userBean) {
        this.name = name;
        this.userBean = userBean;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        CloneBean cloneBean = (CloneBean) super.clone();
        cloneBean.userBean = (UserBean) this.userBean.clone();
        return cloneBean;
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        String name = "CloneBeanName";
        UserBean userBean = new UserBean("OldUserBean");
        CloneBean fromCloneBean = new CloneBean(name, userBean);
        CloneBean toCloneBean = (CloneBean) fromCloneBean.clone();
        toCloneBean.name = "NewBeanName";
        userBean.setName("NewUserBean");
        System.out.println(fromCloneBean.name + "_" + fromCloneBean.userBean + " vs " + toCloneBean.name + "_" + toCloneBean.userBean);
    }
}
//输出结果:CloneBeanName_NewUserBean vs NewBeanName_OldUserBean

1.2 Serializable

对于深层拷贝除了上述所使用的方法,其也可以通过Serializable来间接实现。Seriablizable同Cloneable一样其表示该类的对象是可以被序列化到文件或者在网络流中传播,并被反序列化。
序列化代码如下:

public static <T> void writeObjectToFileName(T src, String filename) throws RuntimeException {
        ObjectOutputStream out = null;
        try {
            out = new ObjectOutputStream(new FileOutputStream(new File(filename)));
            out.writeObject(src);
            out.flush();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (out != null)
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }

    public static <T> T readObjectFromFileName(String filename) throws RuntimeException {
        ObjectInputStream in = null;
        T dist;
        try {
            in = new ObjectInputStream(new FileInputStream(new File(filename)));
            dist = (T) in.readObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (in != null)
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
        return dist;
    }

该段代码实现的功能是将一个对象二进制编码到文件中,并同时提供了新建一个对象,并读取该对象在二进制文件中存取的数据。因此其序列化前后是两个不同的对象。注意:同Cloneable一样,任何可以序列化的对象除本身可以序列化(实现Seriable接口),其域Field也要实现Seriable接口。
如下是一个通过Seriable实现对象深层拷贝的方法:

package com.job.search.blog.code;

import java.io.*;

@SuppressWarnings("unchecked")
public abstract class BeanUtil {

    public static <T> T cloneTo(T src) throws RuntimeException {
        ByteArrayOutputStream memoryBuffer = new ByteArrayOutputStream();
        ObjectOutputStream out = null;
        ObjectInputStream in = null;
        T dist = null;
        try {
            out = new ObjectOutputStream(memoryBuffer);
            out.writeObject(src);
            out.flush();
            in = new ObjectInputStream(new ByteArrayInputStream(memoryBuffer.toByteArray()));
            dist = (T) in.readObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (out != null)
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            if (in != null)
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
        return dist;
    }

    public static <T> void writeObjectToFileName(T src, String filename) throws RuntimeException {
        ObjectOutputStream out = null;
        try {
            out = new ObjectOutputStream(new FileOutputStream(new File(filename)));
            out.writeObject(src);
            out.flush();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (out != null)
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }

    public static <T> T readObjectFromFileName(String filename) throws RuntimeException {
        ObjectInputStream in = null;
        T dist;
        try {
            in = new ObjectInputStream(new FileInputStream(new File(filename)));
            dist = (T) in.readObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (in != null)
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
        return dist;
    }

    public static void main(String[] args) {
        CloneBean fromCloneBean = new CloneBean("OldName", new UserBean("OldUser"));
        CloneBean toCloneBean = BeanUtil.cloneTo(fromCloneBean);
        toCloneBean.setName("NewName");

        System.out.println("Old="+fromCloneBean+" New="+toCloneBean);
    }
}
//输入出结果如下:Old=com.job.search.blog.code.CloneBean@715a64e6 New=com.job.search.blog.code.CloneBean@2b237512
//OldName vs NewName

从结果中可以看出对象已将被深层次的拷贝了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值