JAVA值傳參和引用傳參
這是個老生常談的問題了,經過了先輩們無數的爭論,但是還是沒有提出一個令所有人滿意的答案。當然,我在這裡只是就我自己對Java和其他語言的一些認識談談自己的理解和看法。
首先,我們要明確下面這兩條不可爭論的事實了:
【1】、物件是傳引用的
【2】、基本型別是傳值的
我對這個問題是這樣理解的:
有過C++背景的朋友可能都會有一個認識,因為C/C++傳參有很多種選擇,直接傳遞物件或值,或者傳遞指標,傳遞引用等。而大家都有個共識,那就是在傳遞基本資料型別時,選擇第一種,而傳遞物件的時候則選用傳指標或者引用。這點可以從資料傳輸效率的角度上得到解釋。
而Java創始人James在某些方面還是得借鑑一些C的思想的,所以上述兩條就比較好理解了。
個人對傳參的理解是:
函式引數相對其他欄位,在編譯器裡肯定會有特殊處理的,而一般的編譯器則是這樣處理:
在執行棧中拷貝一份傳遞過來的引數(值參),而後面函式體的關於值參的操作實際上都是針對執行棧裡儲存的備份操作的。可以用這種理解驗證一下C++的三種情況。例如傳遞過來的是引用,則編譯器的處理流程是這樣的:
首先拷貝傳遞來的值參(注意:值參也是引用,Java裡new之後獲得的都是物件的引用,而不是物件本身,這點和c++很不同),然後將其壓入執行棧,後面的操作也就是對這份拷貝(也是對預期的物件的引用,所以可以到達物件)操作了。
我們看看以下的幾個例子來增加對上述思想的理解。
Example1:
執行結果:
---------SWAP UNABLE----------
Int1 is 10
Int2 is 50
我們都知道一點:void swap(int, int)是不能達到交換兩個引數的值的。我們這裡試試使用Integer物件呢?同樣也交換失敗,原因很簡單:void swap(Integer para1, Integer para2)函式傳遞進來的是兩個型別為Integer類的引用,而在函式體裡實現的功能只是改變了para1和para2引用的物件,而para1和para2在記憶體中的值卻一點變化都沒有。可能這樣理解更加形象一點:
例如,A省省長是小王,B省省長是小張,這樣牽強的理解為小王是A省的一個引用,小張則是B省的一個引用。在執行swap(小王,小張)後,產生的效果只是:現在A省省長是小張,B省省長是小王了,即現在小張代表的不再是B省,而是A省了,而對於物件本身,如A省,其地理位置,人口數量等都沒有變化。不能說在swap語句執行後,A省跑到地圖上B省的位置去了吧?
Example2:
執行結果:
---------SWAP UNABLE----------
Int1 is 10
Int2 is 50
---------BEFORE SWAP----------
Int1 is 20
Int2 is 30
---------SWAP ENABLE----------
Int1 is 30
Int2 is 20
首先和上面例子一樣,swap(obj1, obj2)也是換湯不換藥的,所以交換失敗。但是swapx則交換資料成功了,我們還拿上面省長的例子來解釋這個現象:
國家要求小王代表的A省的C市市長和小張代表的B省的D市市長交換職位,可以嗎?當然可以了,所以交換成功。
我們最後再回到Example1的問題,如果我就想交換兩個int值呢?其實也不是沒有辦法的。
執行結果:
---------BEFORE SWAP----------
Int1 is 20
Int2 is 30
---------SWAP ENABLE----------
Int1 is 30
Int2 is 20
小記:
C++:使用分界符&標示引用
C#: 使用ref關鍵字標示引用
好了,關於傳參的問題我的理解就是這樣的。如有錯誤,敬請指出。
首先,我們要明確下面這兩條不可爭論的事實了:
【1】、物件是傳引用的
【2】、基本型別是傳值的
我對這個問題是這樣理解的:
有過C++背景的朋友可能都會有一個認識,因為C/C++傳參有很多種選擇,直接傳遞物件或值,或者傳遞指標,傳遞引用等。而大家都有個共識,那就是在傳遞基本資料型別時,選擇第一種,而傳遞物件的時候則選用傳指標或者引用。這點可以從資料傳輸效率的角度上得到解釋。
而Java創始人James在某些方面還是得借鑑一些C的思想的,所以上述兩條就比較好理解了。
個人對傳參的理解是:
函式引數相對其他欄位,在編譯器裡肯定會有特殊處理的,而一般的編譯器則是這樣處理:
在執行棧中拷貝一份傳遞過來的引數(值參),而後面函式體的關於值參的操作實際上都是針對執行棧裡儲存的備份操作的。可以用這種理解驗證一下C++的三種情況。例如傳遞過來的是引用,則編譯器的處理流程是這樣的:
首先拷貝傳遞來的值參(注意:值參也是引用,Java裡new之後獲得的都是物件的引用,而不是物件本身,這點和c++很不同),然後將其壓入執行棧,後面的操作也就是對這份拷貝(也是對預期的物件的引用,所以可以到達物件)操作了。
我們看看以下的幾個例子來增加對上述思想的理解。
Example1:
- package com.shansun.ref;
- public class RefInteger {
- public RefInteger() {
- }
- public void swap(Integer para1, Integer para2) {
- Integer tmp;
- tmp = para1;
- para1 = para2;
- para2 = tmp;
- }
- public void print(int int1, int int2) {
- System.out.println("Int1 is " + int1);
- System.out.println("Int2 is " + int2);
- }
- public static void main(String[] args) {
- Integer int1 = new Integer(10);
- Integer int2 = new Integer(50);
- RefInteger ref = new RefInteger();
- System.out.println("---------SWAP UNABLE----------");
- ref.swap(int1, int2);
- ref.print(int1, int2);
- }
- }
執行結果:
---------SWAP UNABLE----------
Int1 is 10
Int2 is 50
我們都知道一點:void swap(int, int)是不能達到交換兩個引數的值的。我們這裡試試使用Integer物件呢?同樣也交換失敗,原因很簡單:void swap(Integer para1, Integer para2)函式傳遞進來的是兩個型別為Integer類的引用,而在函式體裡實現的功能只是改變了para1和para2引用的物件,而para1和para2在記憶體中的值卻一點變化都沒有。可能這樣理解更加形象一點:
例如,A省省長是小王,B省省長是小張,這樣牽強的理解為小王是A省的一個引用,小張則是B省的一個引用。在執行swap(小王,小張)後,產生的效果只是:現在A省省長是小張,B省省長是小王了,即現在小張代表的不再是B省,而是A省了,而對於物件本身,如A省,其地理位置,人口數量等都沒有變化。不能說在swap語句執行後,A省跑到地圖上B省的位置去了吧?
Example2:
- package com.shansun.ref;
- public class RefObject {
- int val;
- public RefObject(int val) {
- this.val = val;
- }
- public void setVal(int val) {
- this.val = val;
- }
- public int getVal() {
- return this.val;
- }
- public void print() {
- System.out.println("Now val is " + val);
- }
- public static void swap(RefObject obj1, RefObject obj2) {
- RefObject tmp;
- tmp = obj1;
- obj1 = obj2;
- obj2 = tmp;
- }
- public static void swapx(RefObject obj1, RefObject obj2) {
- int tmp;
- tmp = obj1.getVal();
- obj1.setVal(obj2.getVal());
- obj2.setVal(tmp);
- }
- public static void main(String[] args) {
- RefObject obj1 = new RefObject(10);
- RefObject obj2 = new RefObject(50);
- obj1.print();
- obj2.print();
- swap(obj1, obj2);
- obj1.print();
- obj2.print();
- swapx(obj1, obj2);
- obj1.print();
- obj2.print();
- }
- }
執行結果:
---------SWAP UNABLE----------
Int1 is 10
Int2 is 50
---------BEFORE SWAP----------
Int1 is 20
Int2 is 30
---------SWAP ENABLE----------
Int1 is 30
Int2 is 20
首先和上面例子一樣,swap(obj1, obj2)也是換湯不換藥的,所以交換失敗。但是swapx則交換資料成功了,我們還拿上面省長的例子來解釋這個現象:
國家要求小王代表的A省的C市市長和小張代表的B省的D市市長交換職位,可以嗎?當然可以了,所以交換成功。
我們最後再回到Example1的問題,如果我就想交換兩個int值呢?其實也不是沒有辦法的。
- package com.shansun.ref;
- public class RefInteger {
- int int1, int2;
- public RefInteger(int int1, int int2) {
- this.int1 = int1;
- this.int2 = int2;
- }
- public void swap() {
- int tmp;
- tmp = int1;
- int1 = int2;
- int2 = tmp;
- }
- public void print() {
- System.out.println("Int1 is " + int1);
- System.out.println("Int2 is " + int2);
- }
- public static void main(String[] args) {
- RefInteger ref = new RefInteger(20, 30);
- System.out.println("---------BEFORE SWAP----------");
- ref.print();
- System.out.println("---------SWAP ENABLE----------");
- ref.swap();
- ref.print();
- }
- }
執行結果:
---------BEFORE SWAP----------
Int1 is 20
Int2 is 30
---------SWAP ENABLE----------
Int1 is 30
Int2 is 20
小記:
C++:使用分界符&標示引用
C#: 使用ref關鍵字標示引用
好了,關於傳參的問題我的理解就是這樣的。如有錯誤,敬請指出。
相關文章
- Java傳參傳值Java
- query傳參 和 params傳參方式
- react中路由傳參和url傳參React路由
- Java的值傳遞和引用傳遞Java
- 何時以引用方式傳參
- Vue 路由傳值(傳參)詳解Vue路由
- Golang中函式傳參存在引用傳遞嗎?Golang函式
- 值傳遞和引用傳遞
- python函式的入參和傳參Python函式
- shared_ptr 傳值和傳引用
- Java 從陣列來看值傳遞和引用傳遞Java陣列
- React中this值繫結和事件函式傳參React事件函式
- JavaScript的值傳遞和引用傳遞JavaScript
- Java - 是值傳遞還是引用傳遞Java
- 【SpringMVC】傳參SpringMVC
- [SpringMVC] 傳參SpringMVC
- Day30--值傳遞和引用傳遞
- JavaSE 形參和返回值(引用型別)Java型別
- java靈活傳參之builder模式JavaUI模式
- Vue路由傳參Vue路由
- angular路由傳參Angular路由
- SCSS @mixin傳參CSS
- 傳參問題
- 解惑4:java是值傳遞還是引用傳遞Java
- C#程式設計引用型別和值型別 以及引用傳遞和值傳遞C#程式設計型別
- vue傳參之通過Vue屬性$route的params傳參Vue
- Java方法04:擴充命令列傳參Java命令列
- 關於值傳遞和引用傳遞的解釋
- 這一次,徹底解決Java的值傳遞和引用傳遞Java
- react router路由傳參React路由
- 網頁地址傳參網頁
- Vue查詢傳參Vue
- 你真的理解Python中的賦值、傳參嗎?Python賦值
- C語言中變參函式傳參探究C語言函式
- 這一次,讓你徹底理解Java的值傳遞和引用傳遞!Java
- 快速搞懂值傳遞與引用傳遞
- Vue傳參一籮筐Vue
- JS傳參技巧總結JS
- React事件傳參深度理解React事件