Java基礎--詳解Object類中的clone方法

clone()方法

clone()方法將對象複製了一份並返回給調用者。一般而言,clone()方法滿足:

  1. 對任何對象a,都有a.clone() != a,即克隆對象與源對象不同
  2. 對任何對象a,都有a.clone().getClass == a.getClass,即克隆對象與源對象的類型相同

clone()方法時Object類的一個方法,因此,所有的類都具有這個方法。clone()的作用在於複製對象,在複製對象的過程中,首先要分配一個和源對象同樣大小的空間,在這個空間中創建一個新的對象。

衆所周知,我們可以使用new來創建一個對象,那麼使用new操作符和使用clone方法複製一個對象有什麼區別呢?

new操作符的本質是分配內存,程序執行到new操作符時,首先去看new操作符時,首先去看new操作符後邊的類型,因爲不同的類型分配的內存空間不同,知道了類型就能決定要分配的內存空間多大。然後調用構造函數,填充對象各個域,這一步才叫對象的初始化。構造方法返回後,一個對象創建完畢,可以把他的引用(地址)發佈到外部,在外部就可以使用這個引用來操縱這個對象。而clone在第一步是和new相似的,都是分配內存,調用clone方法時,分配的內存和源對象相同,然後使用源對象中對應的各個域,填充新對象的域。填充完成後,clone方法返回,一個新的相同的對象被創建,同樣可以把這個新對象的引用發佈到外部。

複製引用與複製對象

要注意複製引用和複製對象的區別。這兩者最大的差異在於有沒有在堆區建立一個新的對象。

複製引用

ClassA clazz1 = new ClassA(123);
ClassA clazz2 = clazz1;

上邊的代碼就是一個複製引用,clazz1和clazz2都指向了同一個對象ClassA(123)。我們可以通過這張圖來理解它:

複製對象

ClassA clazz1 = new ClassA(123);
ClassA clazz2 = (ClassA) clazz1.clone();

複製對象也就是通過我們本文的重點clone()方法來實現,出clazz1和clazz2都分別指向一個對象,雖然這兩個對象的內容相同,但地址不同,因此是兩個不同的對象。上圖你就明白了:

很明顯,通過複製對象我們產生了一個新的對象,當我們對克隆的對象進行修改時,並不會影響到源對象,同理,修改源對象也不會影響到克隆對象。

淺複製和深複製

淺複製

淺複製指的是被複制對象的所有變量都含有與原來的對象相同的值,而所有的對其他對象的 引用仍然指向原來的對象。換句話說,淺複製並不關心它所引用的的對象。

例如:類A引用了類B,當我們對類A進行克隆產生一個類C,類C會使用類A原本對類B的引用,即類C直接對類B進行引用。看圖說話:

深複製

被複制對象的所有變量都含有與原來的對象相同的值,除去那些引用其他對象的變量。那些引用其他對象的變量都指向被複制過的新對象,而不是原有的哪些被引用的對象。也就是說,深複製在淺複製的基礎上,將源對象中引用的對象也都複製一遍,用於給克隆對象進行引用。

淺複製和深複製的實現

java.lang.Object類中的clone()方法是淺複製,我們要使用淺複製則直接調用類原有的clone方法即可,那麼我們要如何實現深複製呢?

實現深複製的關鍵就在於覆蓋Object中的clone方法。爲了要在clone對象時進行深複製,那麼就要Cloneable接口,覆蓋並實現clone方法,除了調用父類中的clone方法得到新的對象,還要將該類中的引用變量也clone出來。

public class Test {
	    static class Body implements Cloneable {
	        public Head head;

	        public Body() {
	        }

	        public Body(Head head) {
	            this.head = head;
	        }

	        @Override
	        protected Object clone() throws CloneNotSupportedException {
	            Body newBody = (Body) super.clone();
	            newBody.head = (Head) head.clone();
	            return newBody;
	        }
	    }

	    static class Head implements Cloneable {
	        public Face face;

	        public Head() {
	        }

	        public Head(Face face) {
	            this.face = face;
	        }

	        @Override
	        protected Object clone() throws CloneNotSupportedException {
	            return super.clone();
	        }
	    }

	    static class Face implements Cloneable {
	        public Face() {
	        }
	    }

	    public static void main(String[] args) throws CloneNotSupportedException {
	        Body body = new Body(new Head());
	        Body body1 = (Body) body.clone();
	        System.out.println("body == body1 : " + (body == body1));
	        System.out.println("body.head == body1.head : " + (body.head == body1.head));
	    }
	}

運行main函數的結果爲:

由此可見,我們實現了深複製。但是完全的實現深複製是很難的,如上邊的代碼中,可能Face類中還存在着別的引用,上邊的深複製也是一個不完全的深複製。

本文參考自https://www.cnblogs.com/xzwblog/p/7230788.html

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