1、问题描述
java方法传String类型的参数时,为啥方法对值的修改没有在方法之外生效?假设是其他类型的对象,那么方法对对象的数据的修改是会在方法之外生效的啊,可是String类型也是对象类型啊,为啥就没有在方法之外生效呢?
2、代码示例
//示例1:对象类型
public class PassReferByValue
{
String a = "123";
public static void test(PassReferByValue test)
{
test.a = "abc";
}
public static void main(String[] args)
{
PassReferByValue test = new PassReferByValue();
System.out.println("对象的数据的初始值是:" + test.a); //123
test(test);
System.out.println("通过调用test方法修改对象的数据的值之后:" + test.a); //abc
}
}
总结:因为是对象类型,所以方法每次修改对象的数据的值之后,都在方法之外生效了,也就是说,在方法之外和在方法之内访问到的对象的数据的值是一致的。
//示例2:String类型
public class Test
{
public static void test(String str)
{
str = "word";
}
public static void main(String[] args)
{
String string = "hello";
System.out.println("对象的数据的初始值是:" + string); //hello
test(string);
System.out.println("通过调用test方法修改对象的值之后还是以前的值:" + string); //hello
}
}
总结:如果方法的参数是String类型,虽然方法修改了它的值,但是并没有在方法之外生效,也就是说,在方法之外和在方法之内的访问到的值不一样!!!这是为什么???
3、网上的解释
String等immutable类型因为没有提供自身修改的函数,每次操作都是新生成一个对象,所以要特殊对待。
http://blog.csdn.net/fbysss/article/details/3082949
这样的解释太肤浅了,完全是基于文字的描述,有没有基于代码层面的解释,或者其他的更深层次的解释呢?
按照你的理解思路來講
範例一確實是對
对象的数据的修改
,但是示例二却是对参数本身的修改
了不管是值傳遞還是引用傳遞,其實本質上都是
值传递
,方法呼叫的時候 計算出參數的值,拷貝一份給對應的參數只是對於對象類型,傳遞的是對象的引用(或者理解為指針,地址)值,雖然參數拿到的是拷貝的引用,但是和原引用指向的是同一個對象,因此根據這個引用可以操作到原對象的資料
你的範例二中,呼叫方法時,計算參數
string
的值(可以理解为hello
这个字符串对象在内存中的地址),拷贝给参数str
,参数str
虽然拿到了原来hello
字符串对象的引用(即str
的值等于string
的值,也即hello
的地址),但是立马给这个参数重新赋值,这个时候str
参数已经跟hello
字符串没有任何关系了,str
不再指向hello
,改指向world
了,但是这个过程中hello
自身以及hello
在内存中的地址没有任何变化,方法外部的string
变量也一直指向hello
這個字串對象,沒有任何變化三句話總結一下:
連結描述🎜1.
物件
就是傳引用
对象
就是传引用
2.
原始类型
就是传值
3.
String,Integer, Double
2.原始型別
就是傳值
3.
String,Integer, Double
等immutable類型因為沒有提供自身修改的函數,每次操作都是新產生一個對象,所以要特殊對待。可以認為是傳值。Integer 和 String 一樣。保存value的類別變數是Final屬性,無法被修改,只能被重新賦值/產生新的物件。 當Integer 做為方法參數傳遞進方法內時,對其的賦值都會導致 原Integer 的引用被 指向了方法內的堆疊位址,失去了對原類別變數位址的指向。對賦值後的Integer物件做得任何操作,都不會影響原來物件。
test1.a = "567"
,这里你改的是test1
所引用的物件的屬性str = "word"
你这里改的是引用变量str
所指向的對象。簡單的說,兩個,小明和小紅,你給小明把手換成了機械手,小明的手就真的換了,但是你把小紅改名叫小明……小紅這個人本身還是沒變的。
再深層一點,小明和小紅去參加一個活動,活動不需要知道你的真名,所以給他們分配了代號A和B。這時候,活動中A受傷了,把手換成了機械的,結果活動完了,小明的手確實已經換成機械的了。但B只是把名牌了C進行了交換,出來之後,小紅還是小紅,並沒有變成C對應的那個人。
這裡,活動就是方法,進去分配的代號就是形參,對形參直接賦值不會影響實參,但對形參引用的對象的屬性進行賦值,實際上已經影響到了對象的屬性。
補充一段附註解的程式碼,看能不能幫助你理解。如果要了解方法呼叫的真實過程還涉及棧之類的知識,就不搞那麼複雜了。這段程式碼沒有輸出,你可以在理解之後自己嘗試加一些輸出來驗證自己的理解是否正確。
值傳遞,引用傳遞
Java中除了String,其他的Object都是按引用傳遞。
我的一篇專欄文章的開頭有講到相關知識點,看你有點暈乎乎的,向你推薦一下。
String是immutable類型,也就是說其值是不可變的。例如
String a = "abc"
,在内存中a这个引用指向"abc"这块内存,当使用a = "bcd"
時,並沒有將"abc"所在記憶體區塊的值改為"bcd",而是另外產生一個字串"bcd",然後將a指向"bcd",所以方法外的引用仍然指向"abc"這塊記憶體。而可變的類型,會直接修改"abc"所在記憶體的值,這樣做方法外的引用仍然指向原來的記憶體位址,於是可以在方法外存取到修改後的值。
String物件中包含的字串是不能被修改的,當String類型的變數被重新賦值後,其引用也會發生變化,是一個新的物件了。