之前一直以为自己对java中的string很了解,今天才发现其实自己一点都不了解。直入主题:
public class test {
String a = "123";
public static void change(test test) {
test.a="abc";
}
public static void main(String[] args) {
test test1=new test();
System.out.println(test1.a);
change(test1);
System.out.println(test1.a);
}
}
123
abc
输出的值也正如我们想的那样,因为我们把对象传递了过去,a是对象里的属性,因此我们也可以修改这个属性值。这里是按引用传递值;
public class Test2{
public static void main(String[] args) {
String str = "123";
System.out.println(str);
change(str);
System.out.println(str);
}
public static void change(String str){
str = "abc";
}
}
<span style="font-size:18px;">123</span><br style="font-size:18px;" /><span style="font-size:18px;">123</span>
我们可以看到当我们把str放到主函数里面时输出的结果如上所示,这是为什么呢?change函数并没有改变str的值
首先我们先弄清楚字符串和String类的区别。String类代表字符串。java程序中所有的字符串字面值都是以此类来实现的,如“ABC”。字符串是常量:他们的值在创建后就不能改变。
当我们做了如下操作是
String str;
str = “abc”;
str ="123“;这给我们感觉我们已经改变了他的值,其实不然。引用可以指向不同的常量,在这里是常量池
其实下面这张图完全可以解释上面的那个例子的结果为什么会是那种情况
我们知道java中的String不是基本数据类型,他是引用数据类型,因此有点像c中的指针地址传递,传递的是地址我们可以看到函数中调用的str中的值也是main函数中str内容的拷贝,这里面存的是地址,指向了堆的空间,其实也是值传递,只不过是地址而已。当我们做如下操作是其实我们改变了引用的指向地址,就像我们前面介绍的一样,他并没有
str = "abc";
改变之前的内容,只不过有重新建了一个让str指向新的"abc"的地址
我们看看下面的程序,
public class Test4{
public static void main(String[] args) {
StringBuffer str = new StringBuffer("123");
System.out.println(str);
change(str);
System.out.println(str);
}
public static void change(StringBuffer str){
str = new StringBuffer("abc");
// str.append(abc);
}
}
<pre name="code" class="java">按照上面的分析我们可以得出结论是
123
123
<span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 14px; line-height: 35px;">new一个变量的时候真正的对象其实在堆区,栈上保存了一个指向堆区存放该对象内存的地址。于是在函数调用的时候传递引用也就是传递这个地址值得一个拷贝。通过这个地址值可以修改这个地址所在堆区的内容。切记,传递的这个地址是按值传递的。在函数里面修改这个值得结果就是失去对堆区对象的指向。</span>
<span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 14px; line-height: 35px;">看下面的例子后我相信就会懂了</span>
<span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 14px; line-height: 35px;">public class Test5{
public static void main(String[] args) {
Object o = new Object();
System.out.println(o);
change(o);
System.out.println(o);
}
public static void change(Object o){
o = null;
}
}java.lang.Object@7852e922
java.lang.Object@7852e922
</span>
<span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 14px; line-height: 35px;">输出的结果都是main函数中的变量值,局部变量并没有被打印,这是其作用域决定的此时的局部变量内容改变过一次我们可以这样修改函数</span>
<span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 14px; line-height: 35px;">public class Test5{
public static void main(String[] args) {
Object o = new Object();
System.out.println(o);
change(o);
}
public static void change(Object o){
<span style="white-space:pre"> </span>System.out.println(o);
o = null;
System.out.println(o);
}
}
</span>
<span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 14px; line-height: 35px;">java.lang.Object@7852e922
java.lang.Object@7852e922
null
</span>
<span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 14px; line-height: 35px;">现在我们已经很清楚了在change函数里我们我们用局部变量保存传进来的地址</span><pre name="code" class="java"><span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 14px; line-height: 35px;">o = null;这句让o变量重新指向了一个空的变量导致o的值发生了变化。因为他的对象变了。我们记住引用可指向不同的堆内存地址。</span>
<span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 14px; line-height: 35px;">
</span>
<span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 14px; line-height: 35px;">
</span>
<span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 14px; line-height: 35px;">另外str1==str2比较大的是地址是否为指向同一个对象</span>
<span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 14px; line-height: 35px;">public class Test5{
public static void main(String[] args) {
String string1="ab";
String string2="ab";
String string3=new String("ab");
System.out.println(string1==string2);
System.out.println(string1==string3);
System.out.println(string1.equals(string3));
}
}
</span>
<span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 14px; line-height: 35px;">true string1和string2都指向了常量池中的ab所以地址必然相同,内容也相同
false string3是通过new出来的,是在堆中所以他们的地址必然不相同,也就是指向的不是同一个对象。
true 从内容上我们可以看出来,这三个字符串引用指向对象的内容都相同,所以为true
</span>
<span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 14px; line-height: 35px;">但是我们要清楚在栈中string1 string2 和string3 他们都有自己的地址。</span>
<span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 14px; line-height: 35px;">
</span>