日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java-String类型的参数传递问题

發布時間:2024/4/17 java 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java-String类型的参数传递问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://freej.blog.51cto.com/235241/168676/

剛才看見一個兄弟在為Java的String傳值/傳引用問題困惑,翻箱倒柜找到了這篇我很久以前寫的文章,發在這里,希望能對迷惑的朋友有些幫助。

提要:本文從實現原理的角度上闡述和剖析了:在Java語言中,以String作為類型的變量在作為方法參數時所表現出的“非對象”的特性。 一、最開始的示例 寫代碼最重要的就是實踐,不經過反復試驗而得出的說辭只能說是憑空遐想罷了。所以,在本文中首先以一個簡單示例來拋出核心話題:

public class StringAsParamOfMethodDemo {

????

????????public static void main(String[] args) {

???????????? StringAsParamOfMethodDemo StringAsParamOfMethodDemo =????

???????????????????? new StringAsParamOfMethodDemo();

???????????? StringAsParamOfMethodDemo.testA();

????????}

????

????????private void testA() {

???????????? String originalStr = "original";

???????????? System.out.println("Test A Begin:");

???????????? System.out.println("The outer String: " + originalStr);

???????????? simpleChangeString(originalStr);

???????????? System.out.println("The outer String after inner change: " + originalStr);

???????????? System.out.println("Test A End.");

???????????? System.out.println();

????????}

????

????????public void simpleChangeString(String original) {

???????????? original = original + " is changed!";

???????????? System.out.println("The changed inner String: " + original);

????????}

????

}
? 這段代碼的邏輯是這樣的:先賦值一個String類型的局部變量,然后把這個變量作為參數送進一個方法中,在這個方法中改變該變量的值。編譯運行之后,發現輸出結果是這樣的: Test A Begin: The outer String: original The changed inner String: original is changed! The outer String after inner change: original Test A End. 這個結果表明在方法內部對String類型的變量的重新賦值操作并沒有對這個變量的原型產生任何影響。好了,這個示例的邏輯和運行結果都展示清楚了,接下來我們來對這個小程序進行分析。在這之前我們先來回顧下Java中所謂的“傳值”和“傳引用”問題。 二、Java中的“傳值”和“傳引用”問題 許多初學Java的程序員都在這個問題上有所思索,那是因為這是所謂的“C語言的傳值和傳指針問題”在Java語言上同類表現。 最后得出的結論是: 在Java中,當基本類型作為參數傳入方法時,無論該參數在方法內怎樣被改變,外部的變量原型總是不變的,代碼類似上面的示例:

int number = 0;

changeNumber(number) {number++}; //改變送進的int變量

System.out.println(number); //這時number依然為0 這就叫做“值傳遞”,即方法操作的是參數變量(也就是原型變量的一個值的拷貝)改變的也只是原型變量的一個拷貝而已,而非變量本身。所以變量原型并不會隨之改變。 ?????????????????? 但當方法傳入的參數為基本類型時(也就是說是一個對象類型的變量),方法改變參數變量的同時變量原型也會隨之改變,代碼同樣類似上面的示例:

StringBuffer strBuf = new StringBuffer(“original”);

changeStringBuffer(strBuf) {strbuf.apend(“ is changed!”)} //改變送進的StringBuffer變量

System.out.println(strBuf); //這時strBuf的值就變為了original is changed!???? 這種特性就叫做“引用傳遞”,也叫做傳址,即方法操作參數變量時是拷貝了變量的引用,而后通過引用找到變量(在這里是對象)的真正地址,并對其進行操作。當該方法結束后,方法內部的那個參數變量隨之消失。但是要知道這個變量只是對象的一個引用而已,它只是指向了對象所在的真實地址,而非對象本身,所以它的消失并不會帶來什么負面影響。回頭來看原型變量,原型變量本質上也是那個對象的一個引用(和參數變量是一樣一樣的),當初對參數變量所指對象的改變就根本就是對原型變量所指對象的改變。所以原型變量所代表的對象就這樣被改變了,而且這種改變被保存了下來。 ???????? 了解了這個經典問題,很多細心的讀者肯定會立刻提出新的疑問:“可是String類型在Java語言中屬于基本類型啊!它在方法中的改變為什么沒有被保存下來呢!”的確,這是個問題,而且這個新疑問幾乎推翻了那個經典問題的全部結論。真是這樣么?好,現在我們就來繼續分析。 三、關于String參數傳遞問題的曲解之一——直接賦值與對象賦值 String類型的變量作為參數時怎么會像基本類型變量那樣以傳值方式傳遞呢?關于這個問題,有些朋友給出過解釋,但可惜并不正確。 一種解釋就是,對String類型的變量賦值時并沒有new出對象,而是直接用字符串賦值,所以Java就把這個String類型的變量當作基本類型看待了。即,應該String str = new String(“original”);,而不是String str = “original”;。這是問題所在么?我們來為先前的示例稍微改造下,運行之后看看結果就知道了。改造后的代碼如下: ? ????????private void testB() {

???????????? String originalStr = new String("original");

???????????? System.out.println("Test B Begin:");

???????????? System.out.println("The outer String: " + originalStr);

???????????? changeNewString(originalStr);

???????????? System.out.println("The outer String after inner change: " + originalStr);

???????????? System.out.println("Test B End:");

???????????? System.out.println();

???????????? }

????

????????public void changeNewString(String original) {

???????????? original = new String(original + " is changed!");

???????????? System.out.println("The changed inner String: " + original);

???????????? }

?

我們來看看這次運行結果是怎么樣的: Test B Begin: The outer String: original The changed inner String: original is changed! The outer String after inner change: original Test B End. 實踐證明,這種說法是錯的。 實際上,字符串直接賦值和用new出的對象賦值的區別僅僅在于存儲方式不同。 簡單說明下: 字符串直接賦值時,String類型的變量所引用的值是存儲在類的常量池中的。因為”original”本身是個字符串常量,另一方面String是個不可變類型,所以這個String類型的變量相當于是對一個常量的引用。這種情況下,變量的內存空間大小是在編譯期就已經確定的。 而new對象的方式是將”original”存儲到String對象的內存空間中,而這個存儲動作是在運行期進行的。在這種情況下,Java并不是把”original”這個字符串當作常量對待的,因為這時它是作為創建String對象的參數出現的。 所以對String的賦值方式和其參數傳值問題并沒有直接聯系。總之,這種解釋并不是正解。 四、關于String參數傳遞問題的曲解之二——“=”變值與方法變值 又有些朋友認為,變值不同步的問題是處在改變值的方式上。 這種說法認為:“在Java 中,改變參數的值有兩種情況,第一種,使用賦值號“=”直接進行賦值使其改變;第二種,對于某些對象的引用,通過一定途徑對其成員數據進行改變,如通過對象的本身的方法。對于第一種情況,其改變不會影響到被傳入該參數變量的方法以外的數據,或者直接說源數據。而第二種方法,則相反,會影響到源數據——因為引用指示的對象沒有變,對其成員數據進行改變則實質上是改變的該對象。” 這種方式聽起來似乎有些,我們還是用老辦法,編寫demo,做個小試驗,代碼如下:

private void testC() {

???????????? String originalStr = new String("original");

???????????? System.out.println("Test C Begin:");

???????????? System.out.println("The outer String: " + originalStr);

???????????? changeStrWithMethod(originalStr);

???????????? System.out.println("The outer String after inner change: " + originalStr);

???????????? System.out.println("Test C End.");

???????????? System.out.println();

}

????

????????private static void changeStrWithMethod(String original) {

???????????? original = original.concat(" is changed!");

???????????? System.out.println("The changed inner String: " + original);

} ? 結果如下: ? Test C Begin: The outer String: original The changed inner String: original is changed! The outer String after inner change: original Test C End. ? 怎么樣,這證明了問題并不是出在這,又一個解釋在實踐論據下夭折了。 那到底是什么原因導致了這種狀況呢? 好了,不賣關子了,下面說下我的解釋。 ? 五、String參數傳遞問題的癥結所在 其實,要想真正理解一個類或者一個API/框架的最直接的方法就是看源碼。 下面我們來看看newString對象的那小段代碼(String類中),也就是String類的構造函數: ?

public String(String original) {

????????????????int size = original.count;

????????????????char[] originalValue = original.value;

????????????????char[] v;

????????????????if (originalValue.length > size) {

????????????????????????// The array representing the String is bigger than the new

????????????????????????// String itself.????Perhaps this constructor is being called

????????????????????????// in order to trim the baggage, so make a copy of the array.

????????????????????????????int off = original.offset;

????????????????????????????v = Arrays.copyOfRange(originalValue, off, off+size);

????????????????} else {

????????????????????????// The array representing the String is the same

????????????????????????// size as the String, so no point in making a copy.

????????????????????????v = originalValue;

????????????????}

????????????????this.offset = 0;

????????????????this.count = size;

????????????????this.value = v;

} ? 也許你注意到了里面的char[],這說明對String的存儲實際上通過char[]來實現的。怎么樣?其實就是一層窗戶紙。不知道大家還記不記得在Java API中定義的那些基本類型的包裝類。比如Integerint包裝類、Floatfloat的包裝類等等。對這些包裝類的值操作實際上都是通過對其對應的基本類型操作而實現的。是不是有所感悟了?對,String就相當于是char[]的包裝類。包裝類的特質之一就是在對其值進行操作時會體現出其對應的基本類型的性質。在參數傳遞時,包裝類就是如此體現的。所以,對于String在這種情況下的展現結果的解釋就自然而然得出了。同樣的,IntegerFloat等這些包裝類和String在這種情況下的表現是相同的,具體的分析在這里就省略了,有興趣的朋友可以自己做做試驗。 這也就是為什么當對字符串的操作在通過不同方法來實現的時候,推薦大家使用StringBuffer的真正原因了。至于StringBuffer為什么不會表現出String這種現象,大家再看看的StringBuffer的實現就會明白了,在此也不再贅述了。 六、寫在最后 由此String類型的參數傳遞問題的原理也就展現出來了。其實可以看出,只要分析方式正確,思考終究得出正確結論的。 正確分析方法的基礎有二: 1、多實踐:手千萬不要犯懶,實踐必會出真知。 2、基于原理:搞清楚程序邏輯的最直接最簡單的方式就是看源碼,這毋庸置疑。 只要基于這兩個基礎進行分析,在很多情況下會達到事半功倍的效果。這算是經驗之談吧,也算是分析程序的“捷徑”方式之一。

?

===============http://developer.51cto.com/art/200812/102523.htm

和其它程序設計語言類似,Java語言的參數傳遞也分為兩種:

1.按值傳遞(by value)

適用范圍:8種基本數據類型、String對象

特點:在內存中復制一份數據,把復制后的數據傳遞到方法內部

作用:在方法內部改變參數的值,外部數據不會跟著發生改變

2.按址傳遞(by address)

適用范圍:數組、除String以外的其他所有類型的對象

特點:將對象的地址傳遞到方法內部

作用:在方法內部修改對象的內容,外部數據也會跟著發生改變

基礎示例代碼:

public class Test1{public static void t1(int n){n = 10;}public static void t2(String s){s = "123";}public static void t3(int[] array){array[0] = 2;}public static void main(String[] args){int m = 5;1(m);System.out.println(m);String s1 = "abc";t2(s1);System.out.println(s1);int[] arr = {1,2,3,4};t3(arr);System.out.println(arr[0]);} }

按照上面的參數傳遞規則,該代碼的輸出結果應該是:5 abc 2。因為int類型是按值傳遞,所以把參數m傳遞到方法t1時,相當于又復制了一份m的值,在方法t1內部修改的是復制后的值,所以m的值不變,s1的輸出和m類似。而arr是數組,屬于按址傳遞,也就是把arr的地址傳遞到了方法t3內部,在方法t3內部修改數組中的值時,原來的內容也發生改變。

以上特性是Java語言中的規定,在語法上無法指定參數傳遞是按值傳遞還是按址傳遞,但是可以通過下面的變換實現:

1.對于按值傳遞的參數,如果需要在方法調用以后修改參數的值,可以利用返回值來實現;

2.對于按值傳遞的參數,如果需要在方法內部修改時原來的參數不改變,則可以在方法內部重新創建該對象實現。

示例代碼如下:

public class Test2{public static int t1(int n){n = 10;return n;}public static String t2(String s){s = "123";return s;}public static void t3(int[] array){//創建新的數組并賦值int[] newArray = new int[array.length];//數據拷貝System.arraycopy(array,0,newArray,0,array.length);newArray[0] = 2;}public static void main(String[] args){int m = 5;//重新賦值m = t1(m);System.out.println(m);String s1 = "abc";//重新賦值s1 = t2(s1);System.out.println(s1);int[] arr = {1,2,3,4};t3(arr);System.out.println(arr[0]);} }

這樣,程序的輸出結果就將是:10 123 1。

在實際的程序開發中,可以根據需要使用類似的結構來進行實現。

下面再介紹一個參數傳遞的常見應用,利用參數傳遞實現返回值,這樣的功能在IO類設計的read方法中大量使用。

示例代碼如下:

public class Test3{public static void initArray(int[] array){for(int i = 0;i < array.length;i++){array[i] = i;}}public static void main(String[] args){int[] a = new int[10];initArray(a);for(int i = 0;i < a.length;i++){System.out.println(a[i]);}} }

在該示例代碼中,在initArray方法內部修改了數組的值以后,外部數組a的值也會發生改變,間接實現了返回值的效果。當然,在該示例代碼中,因為只返回一個參數,所以作用體現的不明顯,如果需要返回多個參數時,使用按址傳遞是一種不錯的主意。

因時間倉促,疏漏之處難免,請大家積極補充和指正。

?

總結

以上是生活随笔為你收集整理的Java-String类型的参数传递问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。