Java中的Cloneable接口与深拷贝、浅拷贝

Cloneable接口是一个标记接口,也就是没有任何内容,定义如下:

这里分析一下这个接口的用法,clone方法是在Object种定义的,而且是protected型的,只有实现了这个接口,才可以在该类的实例上调用clone方法,否则会抛出CloneNotSupportExceptionObject中默认的实现是一个浅拷贝,也就是表面拷贝,如果需要实现深层次拷贝的话,必须对类中可变域生成新的实例。

 

Object提供了一个对象拷贝的默认方法clone方法,但是该方法是有缺陷的,它提供了一种浅拷贝方式,也就是它并不会把对象所有属性全部拷贝一份,而是有选择性的拷贝,拷贝规则如下:

1、基本类型

如果变量是基本类型,则拷贝其值,比如:intfloatlong等。

2、String字符串

这个比较特殊,拷贝的是地址,是个引用,但是在修改的时候,它会从字符串池(String Pool)中重新生成新的字符串,原有的字符串对象保持不变,此处可以认为String是个基本类型。

3、对象

如果变量时一个实例对象,则拷贝地址引用,也就是说此时新拷贝出的对象与原有对象共享该实例变量,不受访问权限的限制。这在Java中很疯狂,因为它突破了访问权限的定义,一个private修饰的变量,竟然可以被两个实例对象访问。

Cloneable接口如下:如果调用Object的clone方法,没有实现Cloneable接口,则会抛出CloneNotSupportedException

package java.lang;

/**
 
 * Invoking Object's clone method on an instance that does not implement the
 * <code>Cloneable</code> interface results in the exception
 * <code>CloneNotSupportedException</code> being thrown.
 * 
 * @author  unascribed
 * @see     java.lang.CloneNotSupportedException
 * @see     java.lang.Object#clone()
 * @since   JDK1.0
 */
public interface Cloneable {
}

 

关于clone方法的浅拷贝的一个demo,可以看出虽然是两个不同的ShallowCopy对象,但是对于他们的非基本数据类型的成员变量是属于同一个引用。因此是浅拷贝

package com.yyrookie.test;

import java.util.Date;

public class ShallowCopy implements Cloneable {
    private Date begin;
    public Date getBegin(){
        return this.begin;
    }
    public void setBegin(Date d){
        this.begin = d;
    }
    public Object clone(){
        Object obj = null;
        try{
            obj = super.clone();
        }catch(CloneNotSupportedException ex){
            ex.printStackTrace();
        }
        return obj;
    }
    public static void main(String[] args) {
        Date date = new Date(10000L);
        ShallowCopy copy = new ShallowCopy();
        copy.setBegin(date);
        ShallowCopy copy2 = (ShallowCopy) copy.clone();
        System.out.println(copy.getBegin() + "\n" 
                        + copy2.getBegin() + "\n" + 
                         (copy == copy2));
        date.setTime(100000000L);;
        System.out.println(copy.getBegin() + "\n" 
                + copy2.getBegin() + "\n" + 
                 (copy == copy2));
    }
//    Thu Jan 01 08:00:10 CST 1970
//    Thu Jan 01 08:00:10 CST 1970
//    false
//    Fri Jan 02 11:46:40 CST 1970
//    Fri Jan 02 11:46:40 CST 1970
//    false
}

 相比深拷贝,拷贝对象的同时,又进行了对成员对象进行了深拷贝。

package com.yyrookie.test;

import java.util.Date;

public class DeepCopy implements Cloneable{
    private Date begin;
    public Date getBegin(){
        return this.begin;
    }
    public void setBegin(Date d){
        this.begin = d;
    }
    public Object clone(){
        DeepCopy obj = null;
        try{
            obj = (DeepCopy)super.clone();
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
        }
        obj.setBegin((Date)this.getBegin().clone());
        return obj;
    }
    public static void main(String[] args) {
        Date date = new Date(10000L);
        DeepCopy copy = new DeepCopy();
        copy.setBegin(date);
        DeepCopy copy2 = (DeepCopy) copy.clone();
        System.out.println(copy.getBegin() + "\n" 
                        + copy2.getBegin() + "\n" + 
                         (copy == copy2));
        date.setTime(100000000L);
        System.out.println(copy.getBegin() + "\n" 
                + copy2.getBegin() + "\n" + 
                 (copy == copy2));
    }
//    Thu Jan 01 08:00:10 CST 1970
//    Thu Jan 01 08:00:10 CST 1970
//    false
//    Fri Jan 02 11:46:40 CST 1970
//    Thu Jan 01 08:00:10 CST 1970
//    false
}

 

posted @ 2014-03-07 12:38  yyrookie  阅读(7811)  评论(0编辑  收藏  举报