Day7-22.Assignment

賦值

賦值使用操作符“=”。它的意思是取右邊的值(即右值),把它複製給左邊(即左值)

右值可以是任何常數、變量或者表達式(只要它能生成一個值就行)。

但左值必須是一個明確的、已命名的變量。

也就是說,必須有一個物理空間可以存儲等號右邊的值。

舉例來說,可將一個常熟賦給一個變量:

a=4;

但是不能把任何東西賦給一個常數,常數不能作爲左值(比如不能說4=a;)。

對基本數據類型的賦值是很簡單的。

基本類型存儲了實際的數值,而並非指向一個對象的引用,所以在爲其賦值的時候,是直接將一個地方的內容複製到了另一個地方。

例如,對基本數據類型使用a=b,那麼b的內容就複製給a。

若接着又修改了a,而b根本不會受這種修改的影響。

作爲程序員,這正是大多數情況下我們所期望的。

但是在爲對象“賦值”的時候,情況卻發生了變化。

對一個對象進行操作時,我們真正操作的是對對象的引用。

所以倘若“將一個對象賦值給另一個對象”,實際是將“引用”從一個地方複製到另一個地方。

這意味着假若對對象使用c=d,那麼c和d都指向原本只有d指向的那個對象。

下面這個例子將向大家闡示這一點。

//:operators/Assignment.java

//Assignment with objects is a bit tricky.

import static net.mindview.util.Print.*;


class Tank{

int level;

}

public class Assignment{

public static void main(String[] args){

Tank t1=new Tank();

Tank t2=new Tank();

t1.level=9;

t2.level=47;

print(“1:t1.level:”+t1.level+”,t2.level:”+t2.level);

t1=t2;

print(“2:t1.level:”+t1.level+”,t2.level:”+t2.level);

t1.level=27;

print(“3:t1.level:”+t1.level+”,t2.level:”+t2.level);

}

}/* Output

1:t1.level:9,t2.level:47

2:t1.level:47,t2.level:47

3:t1.level:27,t2.level:27

*///:~

Tank類非常簡單,它的兩個實例(t1和t2)是在main()裏創建的。

對每個Tank類對象的level域都賦予可一個不同的值,然後,將t2賦給t1,接着又修改了t1.

在許多編程語言中,我們可能會期望t1和t2總是相互獨立的。

但由於賦值操作的是一個對象的引用,所以修改t1的同時也改變了t2、

這是由於t1和t2包含的是相同的引用,它們指向相同的對象。

(原本t1包含的對對象的引用,是指向一個值爲9的對象。

在對t1賦值的時候,這個引用被覆蓋,也就是丟失了;而那個不再被引用的對象會由“垃圾回收器”自動清理。)

這種特殊的現象通常稱作“別名現象”,是Java操作對象的一種基本方式。

在這個例子中,如果想避免別名問題應該怎麼辦呢?可以這樣寫:

t1.level=t2.level;

這樣便可以保持兩個對象彼此獨立,而不是將t1和t2綁定到相同的對象。

但你很快就會意識到,直接操作對象內的域容易導致混亂,並且違背了良好的面向對象程序設計的原則。

這可不是一個小問題,所以從現在開始大家就應該留意,爲對象賦值可能會產生意想不到的結果。


Aliasing during method calls 

方法調用中的別名問題

將一個而對象傳遞給方法時,也會產生別名問題:


//:operators/PassObject.java

//Passing objects to methods may not be

//what you’re used to.

import static net.mindview.util.Print.*;

class Letter{

char c;

}

public class PassObject{

static void f(Letter y){

y.c=‘z’;

}

public static void main(String [] args){

Letter x=new Letter();

x.c=‘a’;

print(“1:x.c:”+x.c);

f(x);

print(“2:x.c:”+x.c);

}

}/*Output:

1:x.c:a;

2:x.c:z

*///:~

在許多編程語言中,方法f()似乎要在它的作用域內複製其參數Letter y的一個副本;

但實際上只是傳遞了一個引用。所以代碼行

y.c=‘z’;

實際改變的是f()之外的對象。

別名引起的問題及其解決辦法是很複雜的話題,本書的在線補充材料涵蓋了此話題。

但是你現在就應該知道它的存在,並在使用中注意這個陷阱。


發佈了28 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章