轉載自 這裡
前言 :
來看一段簡單的範例程式 :
猜猜它們的結果會不會一樣!!! 如果你不熟析Java,那麼它的結果可能會讓你有點吃驚 :
在Java中,p2的內容也一併被修改了! 這是因為在Java中,所有的物件,即所有非原生資料型態(primitive data type)的變數,都是參考!
參考是什麼 :
何謂參考(reference)?wiki中對參考的解釋,我覺得寫的不錯:「a reference is an object containing information about how to locate and access the particular data item, as opposed to containing the data itself.」
參考的概念很像指標,它們同樣只保存關於「如何存取某筆資料」的資訊(像是指標中所指向的記憶體位址);但並不保存「該筆資料」本身。
因此,上述的範例中,兩種語言在寫法上雖然非常相似,但是所描述的行為卻是不同的。
我下方的圖簡單說明 :
在C++中,「p2 = p1」的意義是將p1物件的內容複製一份給p2;
然而在Java中,p2與p1都是參考,因此「p2 = p1」的意義是將p1所指向的物件的參考複製一份給p2。
這樣的作法有點類似C/C++中的指標. 若將上述的C++範例改寫為使用指標的話 :
那其行為與結果就會與上述的Java範例中類似了.
C++與Java中的參考 :
每種程式語言對於參考的支援也都不盡相同。
在Java中所有的物件都是一個參考,這是Java的特性之一。Java的參考不支援算術運算,也不能對其取址,不過可以改變該參考所指之處. 像上述的Java範例中,你可以將p2改為指向p3所指向的物件實體 :
如此一來,p2與p3所指向的就是同一個物件實體了. C++中也支援參考,寫法如下 :
事實上,C++的參考,比較常用的場合是在呼叫函式時,傳遞參數給函式的時候,稱為call by reference。在C++的標準函式庫中,很常見到這樣的作法,如srting類別的compare函式 :
int string::compare( const string& str ) const;
這樣做的好處,與C的傳址呼叫(call by address)是一樣的,就是避免傳遞大型資料結構時,複製資料所需的時間. 而需要注意的事也一樣,就是在函式中若修改了該參數的內容,則原本作為參數的變數也會一併被修改。這也是為什麼compare的str參數前面還加上了const.
Java 物件的複製 :
那麼,在Java中,要如何做才能真正複製一個物件呢?答案是使用Object類別的clone方法。
首先你必須先實作Cloneable這個介面 :
public class Point implements Cloneable{
...
幸運的是Cloneable本身並沒有定義任何成員需要實作. 但你還需要覆寫(override)Object類別中的public Object clone()這個方法(method) :
接著,只要把p2 = p1改成 :
Point p2 = (Point) p1.clone();
通常就可以了...為什麼說通常呢?因為物件複製(object copy)的問題還不僅如此, 上例中以super呼叫了父類別Object的clone方法來複製物件,但是Object類別的clone方法執行的是shallow copy,也就是說,如果當欲複製之物件的成員中,也有物件的時候,該成員只會將其參考複製而已!
(反之,則稱為deep copy。)
如果你希望該成員也要進行複製,那麼你也必須針對該成員所屬的類別作一樣的事 : 實作Cloneable介面、覆寫clone方法!
同樣的問題連C++也會遇到,就是當欲複製之物件的成員中,有指標的時候。
C++中的同類別的物件在複製的時候,是透過copy constructor或copy assignment operator,兩者都是C++的special member functions,由編譯器(compiler)自動實作,而有需求的話programmer可自行override.
而預設上,無論是copy constructor還是copy assignment operator都是執行shallow copy。因此,若你希望執行deep copy,則必須將兩者覆寫.
補充說明 :
* [C++ 小學堂] 類別 : 複製構造函數
前言 :
來看一段簡單的範例程式 :
猜猜它們的結果會不會一樣!!! 如果你不熟析Java,那麼它的結果可能會讓你有點吃驚 :
在Java中,p2的內容也一併被修改了! 這是因為在Java中,所有的物件,即所有非原生資料型態(primitive data type)的變數,都是參考!
參考是什麼 :
何謂參考(reference)?wiki中對參考的解釋,我覺得寫的不錯:「a reference is an object containing information about how to locate and access the particular data item, as opposed to containing the data itself.」
參考的概念很像指標,它們同樣只保存關於「如何存取某筆資料」的資訊(像是指標中所指向的記憶體位址);但並不保存「該筆資料」本身。
因此,上述的範例中,兩種語言在寫法上雖然非常相似,但是所描述的行為卻是不同的。
我下方的圖簡單說明 :
在C++中,「p2 = p1」的意義是將p1物件的內容複製一份給p2;
然而在Java中,p2與p1都是參考,因此「p2 = p1」的意義是將p1所指向的物件的參考複製一份給p2。
這樣的作法有點類似C/C++中的指標. 若將上述的C++範例改寫為使用指標的話 :
- Point* p1 = new Point(5,5);
- Point* p2 = p1;
- ...
- p1->setX(500);
- ...
C++與Java中的參考 :
每種程式語言對於參考的支援也都不盡相同。
在Java中所有的物件都是一個參考,這是Java的特性之一。Java的參考不支援算術運算,也不能對其取址,不過可以改變該參考所指之處. 像上述的Java範例中,你可以將p2改為指向p3所指向的物件實體 :
如此一來,p2與p3所指向的就是同一個物件實體了. C++中也支援參考,寫法如下 :
事實上,C++的參考,比較常用的場合是在呼叫函式時,傳遞參數給函式的時候,稱為call by reference。在C++的標準函式庫中,很常見到這樣的作法,如srting類別的compare函式 :
int string::compare( const string& str ) const;
這樣做的好處,與C的傳址呼叫(call by address)是一樣的,就是避免傳遞大型資料結構時,複製資料所需的時間. 而需要注意的事也一樣,就是在函式中若修改了該參數的內容,則原本作為參數的變數也會一併被修改。這也是為什麼compare的str參數前面還加上了const.
Java 物件的複製 :
那麼,在Java中,要如何做才能真正複製一個物件呢?答案是使用Object類別的clone方法。
首先你必須先實作Cloneable這個介面 :
public class Point implements Cloneable{
...
幸運的是Cloneable本身並沒有定義任何成員需要實作. 但你還需要覆寫(override)Object類別中的public Object clone()這個方法(method) :
- public Object clone() throws CloneNotSupportedException {
- return super.clone();
- }
Point p2 = (Point) p1.clone();
通常就可以了...為什麼說通常呢?因為物件複製(object copy)的問題還不僅如此, 上例中以super呼叫了父類別Object的clone方法來複製物件,但是Object類別的clone方法執行的是shallow copy,也就是說,如果當欲複製之物件的成員中,也有物件的時候,該成員只會將其參考複製而已!
(反之,則稱為deep copy。)
如果你希望該成員也要進行複製,那麼你也必須針對該成員所屬的類別作一樣的事 : 實作Cloneable介面、覆寫clone方法!
同樣的問題連C++也會遇到,就是當欲複製之物件的成員中,有指標的時候。
C++中的同類別的物件在複製的時候,是透過copy constructor或copy assignment operator,兩者都是C++的special member functions,由編譯器(compiler)自動實作,而有需求的話programmer可自行override.
而預設上,無論是copy constructor還是copy assignment operator都是執行shallow copy。因此,若你希望執行deep copy,則必須將兩者覆寫.
補充說明 :
* [C++ 小學堂] 類別 : 複製構造函數
This message was edited 2 times. Last update was at 21/03/2011 15:20:31
沒有留言:
張貼留言