我不明白为什么 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
}
答案 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
。
StringBuilder
s是可变的。通过调用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
上的主要操作是append
和insert
方法,它们会被重载以接受任何类型的数据。每个都有效地将给定的数据转换为字符串,然后将该字符串的字符追加或插入字符串生成器。append
方法始终在构建器的末尾添加这些字符;insert
方法在指定点添加字符。
在您的主要方法中,name
和names
仍然是与方法调用之前相同的对象,但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);