按值传递(StringBuilder 与 String)

Pass-by-value (StringBuilder vs String)

我不明白为什么 System.out.println(name) 输出 Sam 而不受方法的 concat 函数的影响,而System.out.println(names) 输出 Sam4 作为方法的附加方法的结果。为什么受影响的是 StringBuilder 而不是 String?通常,对对象引用的调用方法会影响调用者,所以我不明白为什么 String 结果保持不变。提前致谢

public static String speak(String name) {
    name = name.concat("4");
    return name;
}

public static StringBuilder test(StringBuilder names) {
    names = names.append("4");
    return names; 
}

public static void main(String[] args) {
    String name = "Sam";
    speak(name);
    System.out.println(name); //Sam
    StringBuilder names = new StringBuilder("Sam");
    test(names);
    System.out.println(names); //Sam4
}

因为当你打电话给 speak(name); 时,当你打电话时里面会说话

name = name.concat("4");

它创建了一个新对象,因为 Strings 是不可变的。当您更改原始字符串时,它会创建一个新对象,我同意您返回它但您没有捕获它。

所以基本上你正在做的是:

name(new) = name(original) + '4'; // but you should notice that both the names are different objects.

尝试

String name = "Sam";
name = speak(name);

当然现在我认为没有必要解释为什么它与 StringBuilder 一起工作,除非你不知道 StringBuilder 是可变的。

当您调用 speak(name) 时,它会计算新值,但会丢弃它。

如果将其替换为

name = speak(name);

结果将如您所愿。

使用 StringBuilder,您传递的对象是可变的:所以

names.append(names);

更改当前对象的状态(它也是 returns 对同一对象的引用,这只是一种方便,允许您编写 names.append(...).append(...) 等代码)。因此,在 StringBuilder 的情况下,您在调用该方法时引用的对象实际上已经更改,因此您会看到更改。

字符串

String is immutable ( once created can not be changed )object . The object created as a String is stored in the Constant String Pool . Every immutable object in Java is thread safe ,that implies String is also thread safe . String can not be used by two threads simultaneously. String once assigned can not be changed.

String demo = " hello " ; // The above object is stored in constant string pool and its value can not be modified.

demo="Bye" ; //new "Bye" string is created in constant pool and referenced by the demo variable // "hello" string still exists in string constant pool and its value is not overrided but we lost reference to the "hello"string

StringBuilder

StringBuilder is same as the StringBuffer , that is it stores the object in heap and it can also be modified . The main difference between the StringBuffer and StringBuilder is that StringBuilder is also not thread safe. StringBuilder is fast as it is not thread safe .

有关详细信息,请查看 this

结论: 您不需要再次将值重新分配给 StringBuilder 因为它已经是一个参考 测试方法应该是

public static void test(StringBuilder names) {
    names.append("4");
   }

但说话应该是

 String name = "Sam";
   name =  speak(name);

String 在 java 中是不可变的。只要您在名称上调用 concat 方法。创建了一个新字符串,当您在 System.out.println(name) 中使用旧引用时。如果您想使用修改后的字符串,您应该明确 return 引用。 虽然 StringBuilder 是可变的,但它 return 始终是相同的引用。

Javadoc for String,会读到

[...] String objects are immutable [...].

这意味着concat(String)不会改变String本身,而是构造一个新的String

StringBuilders, on the other hand, are mutable. By calling append(CharSequence),对象本身发生变异

因为 String 是不可变的,因此 String#concat 不会修改原始的 String 实例,它只会 returns 一个新的 String 而原始的保持不变,而StringBuilder 是可变的,变化反映在作为参数传递的 StringBuilder 实例中。

在你的方法speak中,concat方法return是一个new String,调用它的原始对象没有改变(字符串是不可变的)。如文件所示:

If the length of the argument string is 0, then this String object is returned. Otherwise, a String object is returned that represents a character sequence that is the concatenation of the character sequence represented by this String object and the character sequence represented by the argument string.

调用name.concat("4")等同于name + "4"

在您的 test 方法中,append 方法 修改了 StringBuilder 的内容 。如文件所示:

The principal operations on a StringBuilder are the append and insert methods, which are overloaded so as to accept data of any type. Each effectively converts a given datum to a string and then appends or inserts the characters of that string to the string builder. The append method always adds these characters at the end of the builder; the insert method adds the characters at a specified point.

在您的主要方法中,namenames 仍然是 与方法调用之前相同的 对象,但是 [=26= 的内容] 未更改,因为字符串是不可变的,而 names 的内容已更改。

如果您使用这两种方法的 return 值,那么您会得到预期的结果。

好的,speak 方法在做什么?

首先,

name.concat("4");

创建新对象,等于 name,与 "4" 连接。

所以,行

name = name.concat(4);

重新定义local(对于speak方法)变量name.

然后你return用

引用这个新值
return name;

所以,在方法中传递的原始变量没有被修改,但是方法return修改了值。

test 方法中,您实际上修改了变量而不修改引用(StringBuilder class 是可变的,因此如果可以修改此类型,则为变量)。

然后我们可以看到另一个问题出现:为什么 StringBuilder.append return 的值,它似乎是多余的。这个问题的答案在于"builder"模式的描述,这是实现修改方法的通常方式。参见 wikipedia on Builder pattern

首先,String是Java中的不可变class。一个 不可变的 class 只是一个 class 的实例不能被修改。实例中的所有信息在实例创建时就已经初始化,不可修改。

其次,在 java 中,参数是按值而不是按引用发送的。

在您的方法 'test' 中,您不需要 names = names.append("4")names.append("4") 就足够了。

如果你检查 java docs 的 String 对象,你会看到那里的大多数方法,包括 concat,都会生成一个新的 String .

所以要在输出 Sam4 上也为字符串,您需要在 main 方法中有这个 name = speak(name).