Java进阶之深入理解深拷贝和浅拷贝

1 Java的clone方法

1.1 为什么需要拷贝?

在实际编程过程中,我们要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值。也就是说,A与B是两个独立的对象,但B的初始值是由A对象确定的。用赋值语句是不能满足这种需求的,而通过实现clone()方法是最简单、最高效的手段。

1.2 什么是拷贝?

Java的所有类都默认继承java.lang.Object类,在java.lang.Object类中有一个方法clone()。JDK API的说明文档解释这个方法将返回Object对象的一个拷贝。要说明的有两点:

(1)拷贝对象返回的是一个新对象,而不是一个引用;
(2)拷贝对象与new新对象的区别就是:①这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息。 ②拷贝效率更高,因为Object类的clone()一个native方法,native方法的效率都是远高于非native方法。

1.2 如何使用clone()?

/**
 * 一个很典型的调用clone()代码如下
 */
public class CloneClass implements Cloneable { 
 public int aInt; 
 
 public Object clone() { 
  CloneClass o = null; 
  try{ 
   o = (CloneClass)super.clone(); 
  } catch(CloneNotSupportedException e) { 
   e.printStackTrace(); 
  } 
  return o; 
 } 
}

有三个值得注意的地方:
(1)希望能实现clone功能的CloneClass类实现了Cloneable接口,这个接口属于java.lang包,java.lang包已经被缺省的导入类中;
(2)重载clone()方法;
(3)在clone()方法中调用super.clone(),指无论clone类的继承结构是什么样的,super.clone()直接或间接调用了java.lang.Object类的clone()方法;
(4)为了让其它类能调用这个clone类的clone()方法,重载之后要把clone()方法的属性设置为public;

2 浅拷贝

2.1 浅拷贝是什么?

浅拷贝:对象A复制出一个对象B来,修改对象B中的8中基本类型(包括装箱)的值和String,对象A中不被修改。修改对象B中的引用对象,由于只拷贝其引用,对象A中的引用对象也会被修改。

2.2 例子

public class AdEntity implements Cloneable {

    public String adTitle;

    public AdEntity(String adTitle) {
        this.adTitle = adTitle;
    }

    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class BookshelfBanner implements Cloneable {
    /**
     * 标题
     */
    public String title;
    /**
     * banner图片url
     */
    public String banner;
    /**
     * 广告实体
     */
    public AdEntity adEntity;

    public BookshelfBanner(String title, AdEntity adEntity) {
        this.title = title;
        this.adEntity = adEntity;
    }

    /**
     * 浅拷贝
     * @return
     */
    public Object clone() {
        BookshelfBanner o = null;
        try {
            o = (BookshelfBanner) super.clone();
        } catch (CloneNotSupportedException e) {
            e.fillInStackTrace();
        }

        return o;
    }
}
public class Test {
    public static void main(String[] args) {
        AdEntity adEntity = new AdEntity("小书亭");
        BookshelfBanner banner1 = new BookshelfBanner("小书亭下载", adEntity);
        BookshelfBanner banner2 = (BookshelfBanner) banner1.clone();

        // banner2.adEntity.adTitle == "小书亭"
        adEntity.adTitle = "小书亭改名啦";              // adEntity引用的adTitle改变了
        // banner2.adEntity.adTitle == "小书亭改名啦"   // 浅拷贝adEntity,会被修改
    }
}

3 深拷贝

3.1 深拷贝是什么?

深拷贝:对象A复制出一个对象B来,修改对象B中的8中基本类型(包括装箱)的值和String,对象A中不被修改。修改对象B中的引用对象,由于引用对象是新创建对象,对象A中的引用对象不会被修改。

3.2 例子

public class AdEntity implements Cloneable {

    public String adTitle;

    public AdEntity(String adTitle) {
        this.adTitle = adTitle;
    }

    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class BookshelfBanner implements Cloneable {

    /**
     * 标题
     */
    public String title;
    /**
     * banner图片url
     */
    public String banner;
    /**
     * 广告实体
     */
    public AdEntity adEntity;

    public BookshelfBanner(String title, AdEntity adEntity) {
        this.title = title;
        this.adEntity = adEntity;
    }

    /**
     * 深拷贝
     *
     * @return
     */
    public Object clone() {
        BookshelfBanner o = null;
        try {
            o = (BookshelfBanner) super.clone();
            if (adEntity != null) {
                o.adEntity = (AdEntity) adEntity.clone();
            }
        } catch (CloneNotSupportedException e) {
            e.fillInStackTrace();
        }

        return o;
    }
}
public class Test {
    public static void main(String[] args) {
        AdEntity adEntity = new AdEntity("小书亭");
        BookshelfBanner banner1 = new BookshelfBanner("小书亭下载", adEntity);
        BookshelfBanner banner2 = (BookshelfBanner) banner1.clone();

        // banner2.adEntity.adTitle == "小书亭"
        adEntity.adTitle = "小书亭改名啦";         // adEntity引用的adTitle改变了
        // banner2.adEntity.adTitle == "小书亭"   // 深拷贝adEntity,不会被修改
    }
}

4 还有一种深拷贝方法,将对象序列化

4.1 对象序列化是什么?

对象序列化却很耗时,在一些框架中,我们便可以感受到,它们往往将对象进行串行化后进行传递,耗时较多。

4.2 例子

public class AdEntity implements Serializable {

    public String adTitle;

    public AdEntity(String adTitle) {
        this.adTitle = adTitle;
    }

    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class BookshelfBanner implements Serializable {

    /**
     * 标题
     */
    public String title;
    /**
     * banner图片url
     */
    public String banner;
    /**
     * 广告实体
     */
    public AdEntity adEntity;

    public BookshelfBanner(String title, AdEntity adEntity) {
        this.title = title;
        this.adEntity = adEntity;
    }

    /**
     * 深拷贝
     *
     * @return
     */
    public Object deepClone() throws IOException, OptionalDataException, ClassNotFoundException {
        // 将对象写到流里
        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        ObjectOutputStream oo = new ObjectOutputStream(bo);
        oo.writeObject(this);
        // 从流里读出来
        ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
        ObjectInputStream oi = new ObjectInputStream(bi);
        return (oi.readObject());
    }
}
public class Test {
    public static void main(String[] args) {
        AdEntity adEntity = new AdEntity("小书亭");
        BookshelfBanner banner1 = new BookshelfBanner("小书亭下载", adEntity);
        BookshelfBanner banner2 = (BookshelfBanner) banner1.deepClone();

        // banner2.adEntity.adTitle == "小书亭"
        adEntity.adTitle = "小书亭改名啦";  // adEntity引用的adTitle改变了
        // banner2.adEntity.adTitle == "小书亭"   // 深拷贝adEntity,不会被修改
    }
}

5 学习链接

Java中的深拷贝(深复制)和浅拷贝(浅复制)

Java的clone方法

浅拷贝和深拷贝(谈谈java中的clone)

发布了185 篇原创文章 · 获赞 207 · 访问量 59万+

猜你喜欢

转载自blog.csdn.net/chenliguan/article/details/88320882
今日推荐