Java語(yǔ)言的一個(gè)優(yōu)點(diǎn)就是取消了指針的概念,但也導致了許多程序員在編程中常常忽略了對象與引用的區別,本文會(huì )試圖澄清這一概念。并且由于Java不能通過(guò)簡(jiǎn)單的賦值來(lái)解決對象復制的問(wèn)題,在開(kāi)發(fā)過(guò)程中,也常常要要應用clone()方法來(lái)復制對象。本文會(huì )讓你了解什么是影子clone與深度clone,認識它們的區別、優(yōu)點(diǎn)及缺點(diǎn)。
看到這個(gè)標題,是不是有點(diǎn)困惑:Java語(yǔ)言明確說(shuō)明取消了指針,因為指針往往是在帶來(lái)方便的同時(shí)也是導致代碼不安全的根源,同時(shí)也會(huì )使程序的變得非常復雜難以理解,濫用指針寫(xiě)成的代碼不亞于使用早已臭名昭著(zhù)的"GOTO"語(yǔ)句。Java放棄指針的概念絕對是極其明智的。但這只是在Java語(yǔ)言中沒(méi)有明確的指針定義,實(shí)質(zhì)上每一個(gè)new語(yǔ)句返回的都是一個(gè)指針的引用,只不過(guò)在大多時(shí)候Java中不用關(guān)心如何操作這個(gè)"指針",更不用象在操作C++的指針那樣膽戰心驚。唯一要多多關(guān)心的是在給函數傳遞對象的時(shí)候。如下例程:
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 changePri(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
*
*/
這段代碼的主要部分調用了兩個(gè)很相近的方法,changeObj()和changePri()。唯一不同的是它們一個(gè)把對象作為輸入參數,另一個(gè)把Java中的基本類(lèi)型int作為輸入參數。并且在這兩個(gè)函數體內部都對輸入的參數進(jìn)行了改動(dòng)??此埔粯拥姆椒?,程序輸出的結果卻不太一樣。changeObj()方法真正的把輸入的參數改變了,而changePri()方法對輸入的參數沒(méi)有任何的改變。
從這個(gè)例子知道Java對對象和基本的數據類(lèi)型的處理是不一樣的。和C語(yǔ)言一樣,當把Java的基本數據類(lèi)型(如int,char,double等)作為入口參數傳給函數體的時(shí)候,傳入的參數在函數體內部變成了局部變量,這個(gè)局部變量是輸入參數的一個(gè)拷貝,所有的函數體內部的操作都是針對這個(gè)拷貝的操作,函數執行結束后,這個(gè)局部變量也就完成了它的使命,它影響不到作為輸入參數的變量。這種方式的參數傳遞被稱(chēng)為"值傳遞"。而在Java中用對象的作為入口參數的傳遞則缺省為"引用傳遞",也就是說(shuō)僅僅傳遞了對象的一個(gè)"引用",這個(gè)"引用"的概念同C語(yǔ)言中的指針引用是一樣的。當函數體內部對輸入變量改變時(shí),實(shí)質(zhì)上就是在對這個(gè)對象的直接操作。
除了在函數傳值的時(shí)候是"引用傳遞",在任何用"="向對象變量賦值的時(shí)候都是"引用傳遞"。如:
package reference;
class PassObj
{
String str = "init value";
}
public class ObjPassvalue
{
public static void main(String[] args)
{
PassObj objA = new PassObj();
PassObj objB = objA;
objA.str = "changed in objA";
System.out.println("Print objB.str value: " + objB.str);
}
}
/* RUN RESULT
Print objB.str value: changed in objA
*/
第一句是在內存中生成一個(gè)新的PassObj對象,然后把這個(gè)PassObj的引用賦給變量objA,第二句是把PassObj對象的引用又賦給了變量objB。此時(shí)objA和objB是兩個(gè)完全一致的變量,以后任何對objA的改變都等同于對objB的改變。
即使明白了Java語(yǔ)言中的"指針"概念也許還會(huì )不經(jīng)意間犯下面的錯誤。
聯(lián)系客服