Java語言的一個優點就是取消了指針的概念,但也導致了許多程序員在編程中經常忽略了對象與引用的區別,本文會試圖澄清這一概念。
并且由于Java不能通過簡單的賦值來解決對象復制的問題,在開發過程中,也經常要要應用clone()方法來復制對象。本文會讓你了解什么是影子clone與深度clone,熟悉它們的區別、優點及缺點。
看到這個標題,是不是有點困惑:Java語言明確說明取消了指針,因為指針往往是在帶來方便的同時也是導致代碼不安全的根源,同時也會使程序的變得非常復雜難以理解,濫用指針寫成的代碼不亞于使用早已臭名昭著的"GOTO"語句。
Java放棄指針的概念絕對是極其明智的。但這只是在Java語言中沒有明確的指針定義,實質上每一個new語句返回的都是一個指針的引用,只不過在大多時候Java中不用關心如何操作這個"指針",更不用象在操作C++的指針那樣膽戰心驚。唯一要多多關心的是在給函數傳遞對象的時候。如下例程:
package reference;
class Obj
{
String str = "init value";
public String toString()
{
return str;
}
}
public class ObjRef
{
Obj aObj = new Obj();
int aInt = 11;
public void changeObj(Obj inObj)
{
inObj.str = "changed value";
}
public void change
PRi(int inInt)
{
inInt = 22;
}
public static void
main(String[] args)
{
ObjRef oRef = new ObjRef();
System.out.println("Before call
changeObj() method:
" + oRef.aObj);
oRef.changeObj(oRef.aObj);
System.out.println
("After call changeObj()
method: " + oRef.aObj);
System.out.println
("==================Print Primtive=================");
System.out.println("Before call
changePri() method: " + oRef.aInt);
oRef.changePri(oRef.aInt);
System.out.println("After call
changePri() method: " + oRef.aInt);
}
}
/* RUN RESULT
Before call changeObj() method:
init value
After call changeObj() method:
changed value
==================Print Primtive=================
Before call changePri() method: 11
After call changePri() method: 11
*
*/
這段代碼的主要部分調用了兩個很相近的方法,changeObj()和changePri()。唯一不同的是它們一個把對象作為輸入參數,另一個把Java中的基本類型int作為輸入參數。并且在這兩個函數體內部都對輸入的參數進行了改動。
看似一樣的方法,程序輸出的結果卻不太一樣。changeObj()方法真正的把輸入的參數改變了,而changePri()方法對輸入的參數沒有任何的改變。
從這個例子知道Java對對象和基本的數據類型的處理是不一樣的。和C語言一樣,當把Java的基本數據類型(如int,char,double等)作為入口參數傳給函數體的時候,傳入的參數在函數體內部變成了局部變量,這個局部變量是輸入參數的一個拷貝,所有的函數體內部的操作都是針對這個拷貝的操作,函數執行結束后,這個局部變量也就完成了它的使命,它影響不到作為輸入參數的變量。
這種方式的參數傳遞被稱為"值傳遞"。而在Java中用對象的作為入口參數的傳遞則缺省為"引用傳遞",也就是說僅僅傳遞了對象的一個"引用",這個"引用"的概念同C語言中的指針引用是一樣的。當函數體內部對輸入變量改變時,實質上就是在對這個對象的直接操作。