关于java:按值传递(StringBuilder与String)

Pass-by-value (StringBuilder vs String)

本问题已经有最佳答案,请猛点这里访问。

我不明白为什么system.out.println(name)在不受方法的concat函数影响的情况下输出sam,而system.out.println(name)在方法的append方法的结果下输出sam4。为什么StringBuilder受到影响而不是String?通常,对对象引用调用方法会影响调用方,因此我不理解为什么字符串结果保持不变。提前谢谢

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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);的时候,当你打电话给speak(name);的时候,内部会说话。

1
name = name.concat("4");

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

所以本质上你所做的是:

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

尝试

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

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


看看JavaDoc for String,你会发现

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

这意味着concat(String)并没有改变String本身,而是构建了一个新的String

另一方面,StringBuilders是可变的。通过调用append(CharSequence),对象本身就发生了变化。


好的,speak方法在做什么?

首先,

1
name.concat("4");

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

所以,这条线

1
name = name.concat(4);

重新定义局部(用于speak方法)变量name

然后返回对这个新值的引用

1
return name;

因此,方法中传递的原始变量不会被修改,但该方法返回修改后的值。

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

然后我们可以看到另一个问题出现了:为什么StringBuilder.append返回值,而这个值似乎是多余的。这个问题的答案在于对"构建器"模式的描述,这是实现修改方法的常用方法。参见维基百科的建设者模式。


在方法speak中,concat方法返回一个新字符串,它调用的原始对象不变(字符串是不可变的)。如文件所示:

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仍然是方法调用之前的同一对象,但name的内容不变,因为字符串是不可变的,而names的内容已更改。

如果您使用了这两个方法的返回值,那么您将得到预期的结果。


由于String是不可变的,因此String#concat不修改原来的字符串实例,它只返回一个新的String,而原来的则保持不变,而StringBuilder是可变的,其变化反映在作为参数传递的StringBuilder实例中。


在Java中,EDCOX1的1Ω是不可变的。一旦对名称调用concat方法。将创建一个新字符串,当您在System.out.println(name)中使用旧的引用时。如果要使用修改后的字符串,应显式返回引用。虽然StringBuilder是可变的,它总是返回相同的引用。


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

如果你把它换成

1
name = speak(name);

结果就是你所期望的。

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

1
names.append(names);

更改当前对象的状态(它还返回对同一对象的引用,这只是方便您编写代码,如names.append(...).append(...)等)。因此,在StringBuilder的情况下,调用方法时所引用的对象实际上已经更改,因此您可以看到更改。


首先,EDCOX1×0是Java中不可变的类。不可变类只是不能修改其实例的类。实例中的所有信息在创建实例时初始化,不能修改。

第二,Java参数是通过值发送的,而不是通过引用发送的。

在你的"测试"方法中,你不需要names = names.append("4"),相反,names.append("4")就足够了。

如果您检查Java对象的字符串对象,您将看到其中的大多数方法,包括CONTAT,将生成一个新的字符串。

因此,要让输出sam4也用于字符串,您需要在主方法中使用这个name = speak(name)


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 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
.

有关详细信息,请检查此

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

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

但说话应该是

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