尽管是字符数组,为什么 String 不能像 "pass by reference" 一样工作

Why does String not work as "pass by reference" in spite of being an array of characters

我了解将数组作为参数传递给函数,并在函数内部对数组元素进行一些更改时,这些更改也会反映在调用函数中,因为数组直接在内存上运行(参考调用)

但是,为什么相同的行为不适用于字符串?我期待字符串也能以同样的方式工作,因为字符串基本上是一个字符数组。

请看下面我的代码。 我将一个 String(字符数组)和一个 int 数组传入一个函数,并对其进行一些更改。在 main 中打印这些时,我看到 String 保持不受影响,而对数组的更改得到反映。

import java.util.Arrays;

public class TestString
{
    public static void main(String[] args)
    {
        String s = "hello";
        int[] a  = new int[5];
        Arrays.fill(a, -1);

        fun(s,a);

        System.out.println(s);
        System.out.println(a[0]);
    }

    static void fun(String s, int[] a)
    {
        s = "world";
        a[0] = 99;
    }
}

输出

hello
99

因为 java 中的字符串是不可变的。对字符串的每一次 "change" 操作都不会改变原始字符串,而是创建一个新的 String 对象。

因为Strings是不可变的。如果你想改变 String 的值,你应该从方法中 return 它并再次将它存储在变量 s 中。

import java.util.Arrays;

public class TestString
{
    public static void main(String[] args)
    {
        String s = "hello";
        int[] a  = new int[5];
        Arrays.fill(a, -1);

        s = fun(s,a);

        System.out.println(s);
        System.out.println(a[0]);
    }

    static String fun(String s, int[] a)
    {
        s = "world";
        a[0] = 99;

        return s;
    }
}

希望对您有所帮助!

Java 不是按引用调用,而是按值调用,只是它将引用作为值传递。 More details here.

字符串是不可变的,因此您无法更改字符串的内容(char 数组),您可以将其替换为不同的内容,即您正在更改引用。但由于引用是按值传递的,因此更改在方法外部不可见。

实际上,您可以使用反射更改 String 的内容,这会产生非常有趣的行为。只有当你想恶作剧同事时才使用它。

首先,String是字符数组的说法是错误的。 String 是一个对象,它具有方法并且被设计为专门不允许对其进行任何更改。

其次,您所做的并没有改变参数的某些元素。您正在更改参数 变量 。参数变量基本上是一个 local 变量,它接收一个 reference 作为参数传递的字符串。这样做:

s = "world";

没有更改传递的字符串。它用新字符串替换局部变量 s 的内容。由于 Java 总是 按值传递,这不会反映在方法之外。如果你有:

a = new int[30];

方法内部。在它外面你仍然会看到你在里面传递的 5 元素 int[]

a[0] = 99;

正在更改数组中的 元素 。所以它查看 a,检查它引用的内容,转到该引用的数组,并更改它的第 0 个元素。

由于String被设计为不可变的,所以没有办法在其中做类似的事情。你不能做这样的事情:

s.setCharacter(0,'a'); // This doesn't exist in Java

但是您可以使用 可变 对象来做到这一点。例如,如果您有:

public static void manipulateStringBuilder( StringBuilder sb ) {
    sb.append(": manipulated");
    sb = new StringBuilder("New value assigned");
}

那么你可以这样写:

StringBuilder sb = new StringBuilder("My string");
System.out.println(sb);
manipulateStringBuilder( sb );
System.out.println(sb);

输出将是:

My string
My string: manipulated

这是因为 StringBuilder 是一个 可变的 对象,再加上您 分配 的值给 sb 在你的方法内部永远不会在它之外出现。