传值(StringBuilder vs String)

时间:2015-07-13 12:01:06

标签: java string parameter-passing stringbuilder pass-by-value

我不明白为什么 System.out.println(name)输出 Sam 而不受方法的concat函数影响,而 System .out.println(名称)输出 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
}

9 个答案:

答案 0 :(得分:12)

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

name = name.concat("4");

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

基本上你正在做的是:

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

尝试

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

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

答案 1 :(得分:9)

查看Javadoc for String,您会发现

  

[...] String对象不可变 [...]。

这意味着concat(String)不会更改String本身,但会构建新的String

另一方面,

StringBuilders是可变的。通过调用append(CharSequence),对象本身就会发生变异。

答案 2 :(得分:4)

好的,speak方法在做什么?

首先,

name.concat("4");

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

所以,行

name = name.concat(4);

重新定义本地(适用于speak方法)变量name

然后使用

返回对此新值的引用
return name;

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

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

然后我们可以看到另一个问题:为什么StringBuilder.append返回值,它看起来多余。这个问题的答案在于" builder"模式,这是实现修改方法的常用方法。请参阅wikipedia on Builder pattern

答案 3 :(得分:3)

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

如果用

替换它
name = speak(name);

结果将是您期望的结果。

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

names.append(names);

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

答案 4 :(得分:3)

String在java中是不可变的。只要在名称上调用concat方法。在System.out.println(name)中使用旧引用时,会创建一个新字符串。如果要使用修改后的字符串,则应显式返回引用。 虽然StringBuilder是可变的,但它总是返回相同的引用。

答案 5 :(得分:3)

因为String是不可变的,因此String#concat不会修改原始的String实例,所以它只返回一个新的String而原始版本未经修改,而StringBuilder是mutable,更改反映在作为参数传递的StringBuilder实例中。

答案 6 :(得分:3)

在方法speak中,concat方法返回 new String ,调用它的原始对象不变(字符串是不可变的)。记录在案:

  

如果参数字符串的长度为0,则返回此String个对象。否则,返回一个String对象,该对象表示一个字符序列,该字符序列是由此String对象表示的字符序列和由参数字符串表示的字符序列的串联。

致电name.concat("4")相当于name + "4"

test方法中,append方法修改了StringBuilder的内容。记录在案:

  

StringBuilder上的主要操作是appendinsert方法,它们会被重载以接受任何类型的数据。每个都有效地将给定的数据转换为字符串,然后将该字符串的字符追加或插入字符串生成器。 append方法始终在构建器的末尾添加这些字符; insert方法在指定点添加字符。

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

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

答案 7 :(得分:2)

首先,String是Java中的不可变类不可变类只是一个无法修改其实例的类。创建实例时,将初始化实例中的所有信息,并且无法修改信息。

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

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

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

因此,对于字符串输出 Sam4 ,您需要在main方法中使用此name = speak(name)

答案 8 :(得分:0)

<强>字符串

  

String是不可变的(一旦创建无法更改)对象。该   作为String创建的对象存储在常量字符串池中。   Java中的每个不可变对象都是线程安全的,这意味着String是   也是线程安全的。两个线程不能使用字符串   同时。分配后的字符串无法更改。

     

String demo =&#34;你好&#34; ; //上面的对象存储在常量中   字符串池及其值无法修改。

     

演示=&#34;再见&#34; ; //新&#34;再见&#34; string是在常量池中创建的   由演变变量引用//&#34;你好&#34;字符串仍然   存在于字符串常量池中,其值不会被覆盖,但我们   失去对&#34; hello&#34;字符串

的引用

<强>的StringBuilder

  

StringBuilder与StringBuffer相同,即存储   堆中的对象,也可以修改它。主要区别   StringBuffer和StringBuilder之间是StringBuilder   也不是线程安全的。 StringBuilder很快,因为它不是线程安全的   

有关详细信息,请查看this

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

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

但是应该说

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