问题描述
- 关于java中String类型参数传递的问题,谁能给我讲清楚
-
我知道java里面参数传递是值传递,这点不用给我解释了。但是:
import java.util.*;public class Test {
public static void change(String s){
s="2";
}
public static void main(String[] args) throws Exception{
String s="1";
change(s);
System.out.println(s);
s="2";
System.out.println(s);
}
}
为什么两次s的值不一样。
希望能从底层原理方面讲的我心服口服,不要讲一些模棱两可的空概念。
你说String是final的,那么为什么在main里面就可以改变。
解决方案
change函数的形参是String 类型,所以是引用地址传值
String s="1";
change(s);
上面首先定义String 变量s="1",然后调用函数方法change,传入实参 s,这里实际传入的仅仅是引用地址 ,也就是"1"的引用地址 ,而不是s本身
,change函数里面s="2" 这句代码中的s是局部变量,并不是外面定义的s,它的引用地址又指向了 "2", 然而外部s变量依旧指向 "1",所以打印依然为1
解决方案二:
http://freej.blog.51cto.com/235241/168676/......
答案就在这里:Java-String类型的参数传递问题
解决方案三:
你第一次输出为1 因为你虽然调用了change()方法 但是你只是调用方法 如果要修改你的S的值 需要有返回 第二次是你将2赋予给了S 所有第二次输出是2 不知道我是否说清楚了 但是意思就是说你调用了change()方法后并没有修改你的S的值
解决方案四:
就是值传递的理解。调用change(s),将S的引用拷贝一份传入方法中,可以理解为第二个引用和原来的S都指向"1"。change方法内部给传入
的第二个引用赋值为“2”,对原有的变量S以及指向的“1”没有任何影响。
String s="1"; ----一个引用S,一个字符串“1”
change(s); ------拷贝S传入方法内部
public static void change(String s){
s="2"; ------------将拷贝的参数S赋值为“2”,不影响原引用。
}
解决方案五:
main函数中的String s="1";执行完后,在jvm的方法区的常量池中会有一个常量1,同时main函数的java栈中会有一个变量s,指向这个1。如图:
当执行change(s)时,只是将main函数中的变量s的值“1”传递给了change函数里的局部变量s。这里容易引起混淆的是,main函数里的s和change函数里的s并不是一个变量,只是两者恰巧名字相同而已,change函数也可以写成这样:change(String str){ str = "2"},折不会影响change函数的功能。因此当执行change(s)是,jvm的情况如下图所示:
由上图可知,当执行change(s)时,修改的是change函数栈中的变量s,和main函数栈中的变量s无关,因此main函数中输出变量s的值当然还是1了。
至于你说的String是final类型的,是不可变的,为什么重新赋值还是会成功呢,原因是这样的。这里的不可变说的是指不可变,但不是指引用不可变。我们知道s="1"是指变量s指向值“1”所在的地址,因为String是final类型的,所以当执行s="2"时,变量会指向常量池中值为2的常量所在的地址,此时s所指向的地址变了。如下图所示:
而如果与String相对的StringBuffer则不同,它不是final类型的,是可变的,所以假设原来有StringBuffer类型的变量sb指向一个值为1的对象所在的地址,而当执行sb="2"时,它只是将原来指向的值为1的对象的值修改成2,sb指向的地址不会变。如下图所示:
StringBuffer sb = "1"
sb="s"
如果你是要调用了change()方法后获得 s="2" 那么 你的change()方法需要又返回值。
解决方案七:
你没有改变引用的那个s,而是让s指向了新的string对象。
引用可以改,引用指向的对象不能改。
你在函数中改变指向没用,因为引用的改变不会影响实参