java經典問題:傳值還是傳引用(轉)
java經典問題:傳值還是傳引用(轉)[@more@]經典的問題,但卻不容易弄懂,尤其對有c基礎的java程式設計師來說,更容易引起混亂,這裡我試圖簡單點描述。
“java函式是傳值的,java函式傳遞的引數是物件的引用”
這兩句話好像初聽上去有些矛盾,但卻是事實,因而引起很多初學者的混亂。在這裡我試圖據個簡單的例子來說明java的這個特性,可能不全面,希望大家來補全。
public class TestRef {
public static void main(String[] args)
{
ValueObject vo1 = new ValueObject("A", 1);
System.out.println("after vo1: " + vo1.getName()); //=A
changeValue1(vo1);
System.out.println("after changeValue1: " + vo1.getName());
//=A1, changed
changeValue2(vo1);
System.out.println("after changeValue2: " + vo1.getName());
//=A1, changeValue2內部的賦值不會影響這裡。
}
/**
* 使用vo1自身的函式對其內部資料進行改變是有效的,函式外可反映出來
* 這種object稱為可變的(mutable)
* @param vo1
*/
private static void changeValue1(ValueObject vo1) {
vo1.setName("A1");
}
/**
* 在函式內給vo1重新賦值不會改變函式外的原始值
* @param vo1
*/
private static void changeValue2(ValueObject vo1) {
vo1 = new ValueObject("B", 2);
System.out.println("inside changeValue2: "+ vo1.getName());
//=B,賦值操作引起的結果變化僅在changeValue2內部有效
}
}
class ValueObject {
public ValueObject() {}
public ValueObject(String name, int id)
{
this.name = name;
this.id = id;
}
private String name;
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
解釋,vo1作為一個object,當它被用作函式引數的時候傳遞給函式的是一個引用值,這個名稱有點怪,又有引用又有值,到底是引用還是值呢,就看你怎麼理解了。如果你是去考試,官方的答案是值。可是看起來又象引用啊,希望從這個例子,你能理解java引數傳遞和和C/C++程式中的引用傳遞的不同的地方。另外,這也是java作為OO語言的特性之一:封裝的體現。
先講一下物件賦值的關係,舉例來說,下列程式碼:
ValueObject v2, v3;
v2 = new ValueObject("C", 3); 粗體的部分建立了一個資料結構,假設存放在記憶體地址A000,賦值給控制程式碼 v2
v3 = new ValueObject("D", 4); 粗體的部分建立了一個資料結構,假設存放在記憶體地址B000,賦值給控制程式碼 v3
v2 = v3; 這句話的作用是把操作B000的地址的控制程式碼的值付給了v2的控制程式碼,使得v2和v3一樣操作B000的地址,這意味著:
1.原來v2指向的地址A000變成無主的記憶體地址,將自動被jvm回收。
2.既然v2和v3指向同一片地址,對v3的修改v2也能得到,反之亦然。
整理得下列程式碼,請感興趣的朋友執行驗證
ValueObject v2 = new ValueObject("C", 3);
ValueObject v3 = new ValueObject("D", 4);
v2 = v3;
System.out.println("after v2=v3");
System.out.println("v2= "+ v2.getName());//=D
System.out.println("v3= "+ v3.getName());//=D
v3.setName("C1");
System.out.println("after v3 setnameTo C1");
System.out.println("vo2= "+ v2.getName());//=C1
System.out.println("vo3= "+ v3.getName());//=C1
因此,可以得出結論,java中物件的每個例項(instance, 比如vo1, v2, v3 都是ValueObject的例項)的記憶體地址是唯一的,它一旦被建立,能夠對這個地址進行操作的就是每個例項自己,如果ValueObject類中沒有public void setName之類的方法對這個類的例項中的資料進行修改的話,程式是沒有任何別的方法可以修改ValueObject類的例項中的資料,這個就是java的封裝特性。對於不提供修改內部資料的方法的類,我們稱為不可變(immutable)的類。在函式中對傳入的引數變數進行賦值操作,只能在函式範圍內改變區域性變數指向的引用地址,但是不會改變原始地址的內容。因此,在changeValue2(...)函式內部的vo1和函式外的vo1雖然名字相同,但是實際上是不同的例項變數,只不過指向了和函式外的vo1同樣的地址,所以當我們用vo1=... 對其進行賦值的時候,只不過是把函式內的臨時變數指向了新的地址,並沒有改變原始vo1記憶體地址中的內容。這就是在執行changeValue2(...)之後,vo1的值在main範圍內仍然沒有被修改的原因。而changeValue1裡面是呼叫的ValueObject本身的function來更改其內容,因此是原始記憶體地址中的資料被更改了,所以是全域性有效的。
“java函式是傳值的,java函式傳遞的引數是物件的引用”
這兩句話好像初聽上去有些矛盾,但卻是事實,因而引起很多初學者的混亂。在這裡我試圖據個簡單的例子來說明java的這個特性,可能不全面,希望大家來補全。
public class TestRef {
public static void main(String[] args)
{
ValueObject vo1 = new ValueObject("A", 1);
System.out.println("after vo1: " + vo1.getName()); //=A
changeValue1(vo1);
System.out.println("after changeValue1: " + vo1.getName());
//=A1, changed
changeValue2(vo1);
System.out.println("after changeValue2: " + vo1.getName());
//=A1, changeValue2內部的賦值不會影響這裡。
}
/**
* 使用vo1自身的函式對其內部資料進行改變是有效的,函式外可反映出來
* 這種object稱為可變的(mutable)
* @param vo1
*/
private static void changeValue1(ValueObject vo1) {
vo1.setName("A1");
}
/**
* 在函式內給vo1重新賦值不會改變函式外的原始值
* @param vo1
*/
private static void changeValue2(ValueObject vo1) {
vo1 = new ValueObject("B", 2);
System.out.println("inside changeValue2: "+ vo1.getName());
//=B,賦值操作引起的結果變化僅在changeValue2內部有效
}
}
class ValueObject {
public ValueObject() {}
public ValueObject(String name, int id)
{
this.name = name;
this.id = id;
}
private String name;
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
解釋,vo1作為一個object,當它被用作函式引數的時候傳遞給函式的是一個引用值,這個名稱有點怪,又有引用又有值,到底是引用還是值呢,就看你怎麼理解了。如果你是去考試,官方的答案是值。可是看起來又象引用啊,希望從這個例子,你能理解java引數傳遞和和C/C++程式中的引用傳遞的不同的地方。另外,這也是java作為OO語言的特性之一:封裝的體現。
先講一下物件賦值的關係,舉例來說,下列程式碼:
ValueObject v2, v3;
v2 = new ValueObject("C", 3); 粗體的部分建立了一個資料結構,假設存放在記憶體地址A000,賦值給控制程式碼 v2
v3 = new ValueObject("D", 4); 粗體的部分建立了一個資料結構,假設存放在記憶體地址B000,賦值給控制程式碼 v3
v2 = v3; 這句話的作用是把操作B000的地址的控制程式碼的值付給了v2的控制程式碼,使得v2和v3一樣操作B000的地址,這意味著:
1.原來v2指向的地址A000變成無主的記憶體地址,將自動被jvm回收。
2.既然v2和v3指向同一片地址,對v3的修改v2也能得到,反之亦然。
整理得下列程式碼,請感興趣的朋友執行驗證
ValueObject v2 = new ValueObject("C", 3);
ValueObject v3 = new ValueObject("D", 4);
v2 = v3;
System.out.println("after v2=v3");
System.out.println("v2= "+ v2.getName());//=D
System.out.println("v3= "+ v3.getName());//=D
v3.setName("C1");
System.out.println("after v3 setnameTo C1");
System.out.println("vo2= "+ v2.getName());//=C1
System.out.println("vo3= "+ v3.getName());//=C1
因此,可以得出結論,java中物件的每個例項(instance, 比如vo1, v2, v3 都是ValueObject的例項)的記憶體地址是唯一的,它一旦被建立,能夠對這個地址進行操作的就是每個例項自己,如果ValueObject類中沒有public void setName之類的方法對這個類的例項中的資料進行修改的話,程式是沒有任何別的方法可以修改ValueObject類的例項中的資料,這個就是java的封裝特性。對於不提供修改內部資料的方法的類,我們稱為不可變(immutable)的類。在函式中對傳入的引數變數進行賦值操作,只能在函式範圍內改變區域性變數指向的引用地址,但是不會改變原始地址的內容。因此,在changeValue2(...)函式內部的vo1和函式外的vo1雖然名字相同,但是實際上是不同的例項變數,只不過指向了和函式外的vo1同樣的地址,所以當我們用vo1=... 對其進行賦值的時候,只不過是把函式內的臨時變數指向了新的地址,並沒有改變原始vo1記憶體地址中的內容。這就是在執行changeValue2(...)之後,vo1的值在main範圍內仍然沒有被修改的原因。而changeValue1裡面是呼叫的ValueObject本身的function來更改其內容,因此是原始記憶體地址中的資料被更改了,所以是全域性有效的。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10617542/viewspace-949436/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Java 是傳值還是傳引用 (轉)Java
- Java - 是值傳遞還是引用傳遞Java
- Java引數傳遞是傳值還是傳引用?Java
- 解惑4:java是值傳遞還是引用傳遞Java
- 偽命題:Java傳遞的值還是引用?Java
- 搗漿糊的老話題:Java是按值傳遞還是按引用傳遞Java
- JS是按值傳遞還是按引用傳遞?JS
- Go語言引數傳遞是傳值?還是傳引用 ?Go
- Go語言引數傳遞是傳值還是傳引用Go
- Java是值傳遞還是引用傳遞,又是怎麼體現的Java
- 面試官問:Go 中的引數傳遞是值傳遞還是引用傳遞?面試Go
- 面試官:兄弟,說說Java到底是值傳遞還是引用傳遞面試Java
- go語言引數傳遞到底是傳值還是傳引用Go
- Python 函式中,引數是傳值,還是傳引用?Python函式
- 188W+程式設計師關注過的問題:Java到底是值傳遞還是引用傳遞?程式設計師Java
- JAVA值傳參和引用傳參Java
- Java的值傳遞和引用傳遞Java
- js中 函式引數的 傳值/傳引用 問題JS函式
- 你會swap嗎,按值傳遞還是按引用?
- Java中的值傳遞和引用傳遞Java
- 關於String是值傳遞還是引用傳遞,talk is cheap, just show codes
- 值傳遞與引用傳遞
- 值傳遞和引用傳遞
- java方法中只有值傳遞,沒有引用傳遞Java
- Java 從陣列來看值傳遞和引用傳遞Java陣列
- 七道最經典的asp.net頁面傳值題ASP.NET
- JavaScript的值傳遞和引用傳遞JavaScript
- 快速搞懂值傳遞與引用傳遞
- java值物件的傳輸問題請教Java物件
- (求教)關於js函式按值、引用傳遞的問題JS函式
- 這裡是值引用還是指標引用?指標
- Java傳參傳值Java
- python中傳值和傳地址問題Python
- Day30--值傳遞和引用傳遞
- GO切片傳值/引用/指標Go指標
- php 傳值與傳引用的理解(通俗易懂)PHP
- 這一次,徹底解決Java的值傳遞和引用傳遞Java
- C#程式設計引用型別和值型別 以及引用傳遞和值傳遞C#程式設計型別