"按引用传递"是什么意思?需要进一步解释。

5
我知道在Java中,所有东西都是按值传递的。但对于对象来说,传递的是对象引用的值。这意味着有时候一个对象可以通过参数被改变,这也就是为什么人们说“永远不要修改参数”的原因。
但在下面的代码中,发生了一些不同的事情。当你回到main()时,changeIt()中的s并没有改变:
public class TestClass {

    static String str = "Hello World";

    public static void changeIt( String s ) {
        s = "Good bye world";
    }

    public static void main( String[] args ) {
        changeIt( str );
        System.out.println( str );
    }
}

我猜测,也希望得到确认,当你说 s = "something" 时,它与说 String s = new String("something") 是相同或等效的。这就是为什么 s 不会改变吗?它被分配了一个新的对象,只在退出 changeIt() 后被丢弃了吗?

1
我之前看过这种问题/答案,但仍然感觉需要复习。+1 - BlackVegetable
它不会改变,因为Java中的字符串是不可变对象。 - anio
1
@anio 不,这不是这段特定代码不改变字符串的原因。对于任何对象,无论是否可变,行为都将相同(因为他正在进行赋值操作,而不是调用接收到的对象上的任何方法)。 - nos
请注意,这个概念与字符串不可变无关!原因是对象引用按值传递,方法有自己独立的引用副本。 - jn1kk
3个回答

4
当你说s = "something"时,这与说String s = new String("something")是相同或等效的。
是的,基本上是这样。 (尽管JVM可能会进行优化,使多次使用相同的字符串文字引用同一个String对象)。
这就是为什么s没有改变的原因吗?它在本地被分配了一个全新的对象,一旦你退出changeIt(),它就被丢弃了。
是的。正如你所说,在Java中,所有内容都按值传递,甚至是对对象的引用。因此,在changeIt(String s)中的变量s是与main()中使用的str不同的值,它只是changeIt方法内的局部变量。 将该引用设置为引用另一个对象不会影响changeIt的调用者。
请注意,在将不同的对象分配给s之前,String对象s所引用的仍然是进入changeIt()方法时str所引用的相同字符串。
还有另一件事情需要注意,那就是字符串是不可变的。这意味着您在字符串对象上调用的任何方法都不会更改该字符串。例如,在changeIt()方法中调用s.toLowerCase()也不会影响调用者。这是因为String.toLowerCase()不会更改对象,而是返回一个新的String对象。

3
当你编写代码时,
s = "Good bye world";

你正在改变s的值,使其成为新字符串的引用。你没有改变被s引用的字符串的值。


0

是的,现在'S'指向全新的对象,其范围仅限于该方法。字符串可能不是理解传值概念的完美例子。我们可以说传递一些可变对象引用,并在其中进行更改以分配新对象。你在对象外看不到它们。

public class MyMain {

    private static void testMyMethod(MyMain mtest) {
        mtest=new MyMain();
        mtest.x=50;
        System.out.println("Intest method"+mtest.x);
    }
     int x=10;
    public static void main(String... args)
    {
        MyMain mtest = new MyMain();
        testMyMethod(mtest);
        System.out.println("In main method: "+mtest.x);
    }
}

阅读Stack Overflow讨论中的第二个答案。


这是错误的,您确实可以看到对可变对象所做的更改:`static Point myPoint = new Point(0,0);public static void changeIt(Point p) { p.setLocation(1,0); }public static void main(String[] args) { changeIt(myPoint); System.out.println(myPoint); }将打印出java.awt.Point[x=1,y=0]`。 - NominSim
@NominSim:请检查我的示例,当您将参数设置为final时,就无法将新对象分配给该引用。 - kosa
当你执行 mtest=new MyMain(); 时,你正在将 mtest 引用到一个新的 Object 上,这与 String 发生的情况相同,因此更改新 Objectx 值不会产生任何影响。从你的代码中删除它,你就会看到更改持久存在,因为它是一个可变的 Object - NominSim
“...传递一些可变对象并在方法内对该对象进行更改。您在对象外部看不到它们。” 这就是我对您原始代码的问题所在,因为更改确实会持续存在于方法之外。当您分配一个新对象时,您不再更改原始对象,这就是为什么它不会更改外部对象的原因。我注意到您已编辑它以反映分配新对象,删除了我的-1。 - NominSim
@NominSim:谢谢!这不仅仅是关于-1的问题。起初我对这个概念有些误解,但在几年前阅读了上面的链接后,一切都变得清晰了。我想确保我们理解一致。 - kosa
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接