前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java中String通过引用传递问题详细解析

Java中String通过引用传递问题详细解析

作者头像
desperate633
发布2018-08-22 15:48:22
6210
发布2018-08-22 15:48:22
举报
文章被收录于专栏:desperate633desperate633

This is a classic question of Java. Many similar questions have been asked on stackoverflow, and there are a lot of incorrect/incomplete answers. The question is simple if you don’t think too much. But it could be very confusing, if you give more thought to it.

这是一个非常经典的问题,许多类似的问题在stackoverflow上被提问,有很多不正确或者不完整的回答。如果你不考虑那么多,直接认为string是immutable的,那问题就很简单,如果你想要了解更多细节,问题就变的很复杂。

我们看下面这个非常容易混淆,同时又很经典的代码

代码语言:javascript
复制
public static void main(String[] args) {
String x = new String("ab");
change(x);
System.out.println(x);
}
public static void change(String x) {
x = "cd";
}

我们可能以为会输出cd,实际上输出的是ab

这是一个很容易混淆的问题,我们来看一下一个貌似很合理的解释:

x stores the reference which points to the "ab" string in the heap. So when x is passed as a parameter to the change() method, it still points to the "ab" in the heap like the following: 变量x存储的是引用,这个引用指向堆上的string“ab”,如下图所示:

image.png

所以x传递给change方法的x参数,然后新建一个string“cd”,然后x有指向这个新建的cd变量

image.png

这样的解释看上去一点问题没有,但为什么输出的结果又不对呢?

真正的代码执行过程应该是这样的:

When the string "ab" is created, Java allocates the amount of memory required to store the string object. Then, the object is assigned to variable x, the variable is actually assigned a reference to the object. This reference is the address of the memory location where the object is stored. 当string变量‘ab’被创建出来的之后,java分配一块足够大小的内存去存储这个string对象,这个对象被分配给变量x,这个变量x实际上存储的是这个对象在内存中的地址。 The variable x contains a reference to the string object. x is not a reference itself! It is a variable that stores a reference(memory address). Java is pass-by-value ONLY. When x is passed to the change() method, a copy of value of x (a reference) is passed. The method change() creates another object "cd" and it has a different reference. It is the variable x that changes its reference(to "cd"), not the reference itself. 这个变量x包含一个这个string对象的一个引用。切记 ** x不是引用本身 **,x只是一个变量存储了一个引用(这个引用其实就是内存的地址)。 java只通过value传递当x被传递给change方法的时候。会将x的一份拷贝传递给change方法中的局部变量x,这是另外一个x,虽然这个x存储的引用也就是地址的值是一样的,待会就被改变了,change方法新建一个对象“cd”,是局部变量里的x指向这个新建cd,所以原本的x还是指向ab。

image.png

我们可以测试其他引用类型的传递,会发现他们实际上都是通过值传递的,会在方法里新建一个引用,当我们对这个引用指向一个新对象时就要注意了

代码语言:javascript
复制
import java.util.ArrayList;
import java.util.List;

public class StringTest {

    public static void main(String[] args) {
        String x = new String("ab");
        change(x);
        System.out.println(x);
        
        Integer y = new Integer(5);
        change(y);
        System.out.println(y);
        
        List<Integer> a = new ArrayList<Integer>();
        
        a.add(1);
        a.add(4);
        change(a);
        
        System.out.println(a);
    }
    
    public static void change(String x) {
        x = "cd";
        }
    
    public static void change(Integer y) {
        y = 4;
    }
    
    public static void change(List<Integer> a) {
        //a.add(5);
        a = new ArrayList<Integer>();
        a.add(2);
        
    }
}

输出结果

image.png

因为我们在方法中都是新建一个对象,所以局部变量的引用都改变了,无法改变原有的值,所以我们看到三个change方法都没有起到作用。

当我们向方法参数传递一个引用的时候要记住是传递的引用的值,而不是引用本身,当我们不让这个引用指向一个新对象的时候,不会出现问题,当我们在方法中将局部的引用赋给一个new出来的对象,那么我们要切记,这时候这个引用已经指向另一个对象了,它所操作的都不会反映在原有的对象上。

那么我们如何解决上面那个问题呢? 其实很简单,只要不在方法里新建一个对象就行了。保持方法中的那个局部变量的引用也在原有对象上操作

代码语言:javascript
复制
public static void main(String[] args) {
StringBuilder x = new StringBuilder("ab");
change(x);
System.out.println(x);
}

public static void change(StringBuilder x) {
x.delete(0, 2).append("cd");
}

我们总结一个关键的问题,Java中没有真正的按引用传递,所有变量都是按值value传递的,引用也是变量,只不过它的值是存的对象的地址。所以引用类型的变量在参数的传递过程中,也会新建一个局部变量,局部变量会得到和引用变量一样的值,也就是指向同一个对象。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.05.29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档