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
值传递
,方法调用的时候 计算出参数的值,拷贝一份给对应的参数🎜 🎜只是对于对象类型,传递的是对象的引用(或者理解为指针,地址)值,虽然参数拿到的是拷贝的引用,但是和原引用指向的是同一个对象,因此根据这个引用可以操作到原对象的数据🎜 🎜你的示例二中,调用方法时,计算参数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
所引用的对象的属性test1.a = "567"
,这里你改的是test1
所引用的对象的属性str = "word"
你这里改的是引用变量str
str = "word"
你这里改的是引用变量str
所指向的对象。值传递,引用传递
Java中除了String,其他的Object都是按引用传递。
我的一篇专栏文章的开头有讲到相关知识点,看你有点晕乎乎的,向你推荐一下。
String是immutable类型,也就是说其值是不可变的。例如
String a = "abc"
,在内存中a这个引用指向"abc"这块内存,当使用a = "bcd"
时,并没有将"abc"所在内存块的值改为"bcd",而是另外生成一个字符串"bcd",然后将a指向"bcd",所以方法外的引用仍然指向"abc"这块内存。而可变的类型,会直接修改"abc"所在内存的值,这样做方法外的引用仍然指向原来的内存地址,于是可以在方法外访问到修改后的值。
String对象中包含的字符串是不能被修改的,当String类型的变量被重新赋值后,其引用也会发生变化,是一个新的对象了。