1. 程式人生 > >Java中的Object類 (下篇)

Java中的Object類 (下篇)

 要麼讀書,要麼旅行,身體和心靈總有一個要在路上。——羅馬假日

 上篇我們講了hashCode和equals方法,首先我們先回顧一下

  1. hashCode是根據一定的規則和物件相關的資訊對映成一個數值,這個數值成為雜湊值。他是由native關鍵字修飾的,native關鍵字主要是Java平臺與本地C程式碼進行互動的API,即為Java Native Interface(JNI)。
  2. equals關鍵字是用來比較物件是否相等的。如果使用Object的equals方法,實際上比較的是兩個物件的記憶體地址是否相同,這與我們的初衷往往不一樣。我們常見的型別,如String,Integer,Long等,JDK都為我們重寫了equals方法,所以我們可以直接使用equals方法來實現物件數值的比較。如果是我們自定義的物件,就要手動重寫equals方法。

如有不明白,可以看我另外一篇文章哈。傳送門來了,Java中的Object類 (上篇)

今天我講clone方法,他的作用就是快速建立一個已有物件的副本,克隆後的物件型別與被克隆物件的型別相同。

咱先簡單使用:

public class Person implements Cloneable {
  private String id;
  private String name;

  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

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

  @Override
  protected Person clone() throws CloneNotSupportedException {
    return (Person) super.clone();
  }
}
public class Test {
  public static void main(String[] args){
     Person person1=new Person();
     person1.setId("1");
     person1.setName("張三");
     System.out.println("修改前的person1:"+person1.getId()+","+person1.getName());
     try {
       Person person2=person1.clone();
       System.out.println("修改前的person2:"+person2.getId()+","+person2.getName());
       person2.setId("2");
       person2.setName("李四");
       System.out.println("修改後的person2:"+person2.getId()+","+person2.getName());
       System.out.println("修改後的person1:"+person1.getId()+","+person1.getName());
     }catch (Exception e){
       e.printStackTrace();
     }
  }
}

我們來看一下,這些程式碼到底幹了啥呢。

首先Person類重寫了clone方法,同時也丟擲了cloneNotSupportedException這個異常,也就是說這個這個類不支援cloneable介面,就會丟擲異常,這也就解釋了Person實現了Cloneable介面。

其次我們看一下clone方法裡面,也就是呼叫了父類Object的clone方法。

最後我們看一下測試類Test,先定義了一個person1物件,併為其賦值,id為1,name為張三,這第一行輸出沒啥問題。然後呼叫Person類的clone方法,實現賦值的功能,產生了person2物件,第二行輸出也沒問題。再修改了person2物件,id為2,name為李四,第三行也就輸出了修改後的值。最後輸出了person1物件的值。

這整個過程看下來,clone在這個過程中實現了深克隆,也就是person1和person2是兩個完全不同的物件,他們互不干擾。

咱來試試複雜一點的,看程式碼咯

public class Clothes {
  private String color;
  private String size;

  public String getColor() {
    return color;
  }

  public void setColor(String color) {
    this.color = color;
  }

  public String getSize() {
    return size;
  }

  public void setSize(String size) {
    this.size = size;
  }

  public Clothes(String color, String size) {
    this.color = color;
    this.size = size;
  }
}
public class Person implements Cloneable {
  private String name;
  private Clothes clothes;

  public String getName() {
    return name;
  }

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

  public Clothes getClothes() {
    return clothes;
  }

  public void setClothes(Clothes clothes) {
    this.clothes = clothes;
  }

  public Person(String name, Clothes clothes) {
    this.name = name;
    this.clothes = clothes;
  }

  @Override
  public Person clone() throws CloneNotSupportedException {
    return (Person) super.clone();
  }
}
public class Test {
  public static void main(String[] args) {
    Person person1 = new Person("張三", new Clothes("紅", "m號"));
    System.out.println("修改前的person1:name("+person1.getName()+"),clothes("+person1.getClothes().getColor()+","+person1.getClothes().getSize()+")");
    try {
      Person person2 = (Person) person1.clone();
      System.out.println("修改前的person2:name("+person2.getName()+"),clothes("+person2.getClothes().getColor()+","+person2.getClothes().getSize()+")");
      person2.setName("李四");
      person2.getClothes().setColor("藍");
      person2.getClothes().setSize("l號");
      System.out.println("修改後的person2:name("+person2.getName()+"),clothes("+person2.getClothes().getColor()+","+person2.getClothes().getSize()+")");
      System.out.println("修改後的person1:name("+person1.getName()+"),clothes("+person1.getClothes().getColor()+","+person1.getClothes().getSize()+")");
    } catch (CloneNotSupportedException e) {
      e.printStackTrace();
    }
  }
}

這幾個類描述了一個person類和clothes類,學生類中包括成員變數name和clothes。person類中重寫了clone()方法,而clothes類並沒有重寫clone方法。

我們看一下執行結果,person2是由person1克隆過來的,所以輸出語句的第一行和第二行,屬性值是一樣的。然後修改了person2的name值和clothes值,結果person1的name值沒有改變,還是原來的張三,而clothes值並變成了藍,l號。

這說明其實呼叫Object類的clone方法,是在記憶體上開闢一塊和原始物件一樣的空間,然後原樣拷貝原始物件的內容,對於基本的資料型別來說,是沒有物件的(就像剛才的示例一樣,在修改完person2的name和clothes後,person1的name並沒有改變,還是原來的張三)。但對於非基礎型別來說,他儲存的只是物件的引用(就像剛才的示例,在修改完person2的name和clothes後,person1的clothes發生了變化)。

解決方法:

將非基礎型別也重寫clone方法,實現引用克隆。至於程式碼,就在上面Clothes類裡面加上重寫的程式碼就ok啦,我就不寫了哦。