Java的clone方法--深拷貝和淺拷貝

Cloneable接口是一個標記接口,也就是沒有任何內容,定義如下:

這裏分析一下這個接口的用法,clone方法是在Object種定義的,而且是protected型的,只有實現了這個接口,纔可以在該類的實例上調用clone方法,否則會拋出CloneNotSupportExceptionObject中默認的實現是一個淺拷貝,也就是表面拷貝,如果需要實現深層次拷貝的話,必須對類中可變域生成新的實。

Object提供了一個對象拷貝的默認方法clone方法,但是該方法是有缺陷的,它提供了一種淺拷貝方式,也就是它並不會把對象所有屬性全部拷貝一份,而是有選擇性的拷貝,拷貝規則如下:

1、基本類型

如果變量是基本類型,則拷貝其值,比如:intfloatlong等。

2、String字符串

這個比較特殊,拷貝的是地址,是個引用,但是在修改的時候,它會從字符串池(String Pool)中重新生成新的字符串,原有的字符串對象保持不變,此處可以認爲String是個基本類型。

3、對象

如果變量時一個實例對象,則拷貝地址引用,也就是說此時新拷貝出的對象與原有對象共享該實例變量,不受訪問權限的限制。這在Java中很瘋狂,因爲它突破了訪問權限的定義,一個private修飾的變量,竟然可以被兩個實例對象訪問。

public class Client {
    public static void main(String[] args){
        //定義父親
        Person p = new Person("父親");
        //定義大兒子
        Person son1 = new Person("大兒子",p);
        //定義小兒子
        Person son2 = son1.clone();
        //重新給son2起名
        son2.setName("小兒子");
          
        //給小兒子,找個乾爹
        son2.getFather().setName("乾爹");
          
        System.out.println(son1.getName()+" 的父親是 "+son1.getFather().getName());
        System.out.println(son2.getName()+" 的父親是 "+son2.getFather().getName());
    }
}
class Person implements Cloneable{
      
    private String name;
      
    private Person father;
      
    public Person(String name){
        this.name=name;
    }
      
    public Person(String name,Person father){
        this.name=name;
        this.father=father;
    }
      
    //拷貝的實現
    @Override
    public Person clone(){
        Person p = null;
        try{
            //調用Object的淺拷貝
            p = (Person) super.clone();
              
            /**
             * 1.重新覆寫對象實例部分的拷貝,實現深拷貝
             * 2.如果沒有重寫對象實例部分的拷貝,那麼大兒子和小兒子的父親會引用同一個父親,
             * 只要任意修改一下父親,另外一個就會被修改
             */
            p.setFather(new Person(p.getFather().getName()));
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
        }
        return p;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Person getFather() {
        return father;
    }
    public void setFather(Person father) {
        this.father = father;
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章