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
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM