JAVA隨筆篇二(深入分析JAVA簡單類型、String和對象的值傳遞和引用傳遞)

來源:互聯網
上載者:User

標籤:java   值傳遞   引用傳遞   

關於JAVA的值傳遞和引用傳遞,翻看了很多資料和部落格,感覺大多數講的很亂,都是自己明白了之後就不講了的樣子,終於算是比較理解這幾個概念了,下面做一個總結。


1、簡單類型的參數傳遞

Java方法的參數是簡單類型的時候,是按值傳遞的 (pass by value)。下面舉一個經典的swap函數:

無法交換值的方法

package TestTransferPack;public class TestTransfer {public static void main(String[] args) {// TODO Auto-generated method stubint a = 1;int b = 5;swap(a, b);System.out.println(a+"  "+ b);}public static void swap(int a,int b){int temp=0;temp = b;b=a;a=temp;}}
result:1  5
以參數形式傳遞簡單類型的變數時,實際上是將參數的值作了一個拷貝傳進方法函數的,那麼在方法函數裡再怎麼改變其值,其結果都是只改變了拷貝的值,而不是源值。

交換值的方法:

(1)數組

package TestTransferPack;public class TestTransfer1 {public static void main(String[] args) {// TODO Auto-generated method stubint a = 1;int b = 5;int[] test = new int[2];test[0]=a;test[1]=b;swap(test,0, 1);a = test[0];b = test[1];System.out.println(a+"  "+ b);}public static void swap(int[] data,int index1,int index2){   int tmp = data[index1];   data[index1] = data[index2];   data[index2] = tmp;}}
result:5  1

這種利用數組的方式可以改變兩個簡單類型的值。

C++中有指標,簡單類型的傳遞方式和1中的一樣,都是值傳遞,但是卻可以通過傳遞指標的方式交換兩個簡單類型的值,但是JAVA中沒指標,所以簡單類型的值交換要特殊處理。

2、普通對象的參數傳遞
普通對象一般是按照引用傳遞的,姑且先這樣說,也就是大家說的按地址傳遞, 地址傳遞傳遞的就是原來的對象地址,這樣修改內容就會改變原值,後面會對這種傳遞方式做詳細分析解釋。

package TestTransferPack;public class TestTransfer2 {public static void main(String[] args) {// TODO Auto-generated method stubint a = 1;int b = 5;Test tt1 = new Test(a);Test tt2 = new Test(b);swap1(tt1,tt2);System.out.println(tt1.a+"  "+ tt2.a);}public static void swap1(Test index1,Test index2){int tmp = index1.a;index1.a = index2.a;index2.a = tmp;}public static class Test{int a=0;public Test(int b){a = b;}}}

result: 5  1

可以看出,在函數中兩個對象的資料是可以修改的。

然而這樣卻不能改變對象的值:

package TestTransferPack;public class TestTransfer3 {public static void main(String[] args) {// TODO Auto-generated method stubint a = 1;int b = 5;Test tt1 = new Test(a);Test tt2 = new Test(b);swap1(tt1,tt2);System.out.println(tt1.a+"  "+ tt2.a);}public static void swap1(Test index1,Test index2){/*int tmp = index1.a;index1.a = index2.a;index2.a = tmp;*/Test tmp = new Test();tmp = index1;index1 = index2;index2 = tmp;}public static class Test{int a=0;public Test(int b){a = b;}public Test(){}}}
result: 1  5
究其原因,我們可以將去推及C++的參數傳遞,C++中如果參數傳遞的是一個指標,那麼這個指標指向的對象內容可以改變,但是指標本身確是一個複製,因此不能改變指標的值;JAVA中對象的參數傳遞是一個地址,這個地址指向的內容是可以改變的,就像上面TestTransfer2中的例子,但是這個地址卻是按值傳遞的,改變這個地址完全沒有用,就像TestTransfer3中一樣。
大家通常舉String做為特殊的對象來說明對象是按值或者按引用傳遞,卻往往說的亂七八糟,通常是自己明白之後就亂寫,下面一節再討論String的問題。本人也不甚精通,如果寫的有什麼不對的,歡迎指正。

3、String及相關對象的參數傳遞

通俗來說,String是按照值傳遞的。

package TestTransferPack;public class TestTransfer4 {public static void main(String[] args) {// TODO Auto-generated method stubString tt1 = new String("hello ");String tt2 = new String("world ");swap1(tt1,tt2);System.out.println(tt1 + tt2);}public static void swap1(String index1,String index2){String tmp = index1;index1 = index2;index2 = tmp;}}result:hello world

這和TestTransfer3是一樣的,當然不能改變String的值,有人說用StringBuffer,當然也不能。

package TestTransferPack;public class TestTransfer5 {public static void main(String[] args) {// TODO Auto-generated method stubStringBuffer  tt1 = new StringBuffer ("hello ");StringBuffer  tt2 = new StringBuffer ("world ");swap1(tt1,tt2);System.out.println(tt1.toString()+ tt2.toString());}public static void swap1(StringBuffer  index1,StringBuffer  index2){StringBuffer tmp = index1;index1 = index2;index2 = tmp;}}
<pre name="code" class="java">result:hello world

可能會想到在函數中改變index1的值,比如index1=index2,但是String和StringBuffer都不行,改變的值並不能帶出函數。

但是這樣卻可以:

package TestTransferPack;public class TestTransfer6 {public static void main(String[] args) {// TODO Auto-generated method stubStringBuffer  tt1 = new StringBuffer ("hello ");StringBuffer  tt2 = new StringBuffer ("world ");append(tt1,tt2);System.out.println(tt1.toString()+ tt2.toString());}public static void append(StringBuffer  index1,StringBuffer  index2){index1.append(index2);}}
result:hello world world 
下面看一下append的實現,一路追蹤下去,我們會找到這句話:

System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
使用這個方法之前先擴充了StringBuffer的數組大小,然後copy資料。這樣,就會改變index1指向的空間的內容。

都說String在賦值操作的過程中產生新的對象,這樣的話,TestTransfer4和TestTransfer5中的問題就迎刃而解了,因為都不是一個對象,怎麼可能改變這個值。

下面探討一下。

我們知道,hashCode是object的唯一標識。我們可以用 hashCode來確定String在賦值或者其他動作中的對象變化。

package TestTransferPack;public class TestTransfer7 {public static void main(String[] args) {// TODO Auto-generated method stubStringBuffer  tt1 = new StringBuffer ("hello ");StringBuffer  tt2 = new StringBuffer ("world ");append(tt1,tt2);System.out.println(tt1.toString()+ tt2.toString());System.out.println(tt1.hashCode());}public static void append(StringBuffer  index1,StringBuffer  index2){index1.append(index2);System.out.println(index1.hashCode());index1 = index2;System.out.println(index1.hashCode());}}
result:11671659211442002549hello world world 1167165921
可以看出,index1在第二次賦值之後就不再是原對象。String也是一樣。








著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

JAVA隨筆篇二(深入分析JAVA簡單類型、String和對象的值傳遞和引用傳遞)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.