为什么修改了ArrayList参数,但没有修改String参数?

Nar*_*esh 25 java parameters pass-by-reference call-by-value

public class StackOverFlow {
    public static void main(String[] args) {
        ArrayList<String> al = new ArrayList<String>();
        al.add("A");
        al.add("B");
        markAsNull(al);
        System.out.println("ArrayList elements are "+al);

        String str = "Hello";
        markStringAsNull(str);
        System.out.println("str "+ str);
    }
    private static void markAsNull(ArrayList<String> str){
        str.add("C");
        str= null;
    }
    private static void markStringAsNull(String str){
        str = str + "Append me";
        str = null;
    }
}
Run Code Online (Sandbox Code Playgroud)

这输出:

ArrayList elements are [A, B, C]
str Hello
Run Code Online (Sandbox Code Playgroud)

在这种情况下ArrayList,添加的元素将被检索.如果String方法调用对传递的String没有影响.JVM到底在做什么?谁能详细解释一下?

Azo*_*ous 21

在Arraylist字符串对象的情况下,添加的元素将被重新获得.对于String,方法调用对传递的String没有影响.

它发生的原因是Java是Pass-by-Value而且Strings是不可变的

你打电话的时候

markAsNull(ArrayList<String> str)
Run Code Online (Sandbox Code Playgroud)

按名称的一个新的参考str是为同一创建ArrayList的指向al.当你上面add的元素str被添加到同一个对象时.后来你把strnull但对象已经添加了新的价值观和被指出a1.

你打电话的时候

markStringAsNull(String str)
{
    str = str + "Append me";
    // ...
}
Run Code Online (Sandbox Code Playgroud)

该行通过附加给定的字符串并将其分配给str = str + "Append me";String对象str.但同样它只是引用现在指向新创建的字符串的实际字符串.(由于immutablity)并且原始字符串没有改变.

  • 这不是因为字符串是不可变的,而是因为 `str = &lt;something&gt;` 与 `list.&lt;something&gt;`。 (2认同)

Why*_*rrh 5

markXAsNull方法是设置本地引用是null.这对存储在该位置的实际值没有影响.该main方法仍然有自己对值的引用,可以println使用它们调用.

此外,在进行字符串连接时,toString()正在对象上调用,这就是为什么ArrayList作为括号中的值列表输出的原因.


Sik*_*ski 5

来自本书:SCJP - Sun Certified Programmer for Java 6 Study Guide (Katty Sierra - Bert Bates) 第 3 章目标 7.3 - 将变量传递给方法

Java 实际上是对在单个 VM 中运行的所有变量进行值传递。按值传递意味着按变量值传递。这意味着,传递变量的副本!

传值的底线:被调用的方法不能改变调用者的变量,尽管对于对象引用变量,被调用的方法可以改变变量引用的对象。改变变量和改变对象有什么区别?对于对象引用,这意味着被调用的方法不能重新分配调用者的原始引用变量并使其引用不同的对象,或者为 null。例如,在下面的代码片段中,

void bar() {
Foo f = new Foo();
doStuff(f);
}
void doStuff(Foo g) {
g.setName("Boo");
g = new Foo();
}
Run Code Online (Sandbox Code Playgroud)

重新分配 g 不会重新分配 f!在 bar() 方法的末尾,已经创建了两个 Foo 对象,一个由局部变量 f 引用,另一个由局部(参数)变量 g 引用。因为 doStuff() 方法有一个引用变量的副本,所以它有一种获取原始 Foo 对象的方法,例如调用 setName() 方法。但是, doStuff() 方法无法访问 f 引用变量。所以 doStuff() 可以改变 f 所指对象内的值,但是 doStuff() 不能改变 f 的实际内容(位模式)。换句话说,doStuff() 可以改变 f 所引用的对象的状态,但它不能让 f 引用不同的对象!

  • 尽管SO的惯例反对它,但我还是忍不住在你的回答下发表了我的赞赏:) (2认同)