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

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的,那问题就很简单,如果你想要了解更多细节,问题就变的很复杂。

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

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

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

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出来的对象,那么我们要切记,这时候这个引用已经指向另一个对象了,它所操作的都不会反映在原有的对象上。

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

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传递的,引用也是变量,只不过它的值是存的对象的地址。所以引用类型的变量在参数的传递过程中,也会新建一个局部变量,局部变量会得到和引用变量一样的值,也就是指向同一个对象。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,924评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,781评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,813评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,264评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,273评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,383评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,800评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,482评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,673评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,497评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,545评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,240评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,802评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,866评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,101评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,673评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,245评论 2 341

推荐阅读更多精彩内容