我不明白为什么System.out.println(name)输出Sam而不受方法的concat函数的影响,而System.out.println(names)输出Sam4作为方法的append方法的结果。为什么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");
创建一个新对象,因为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
是可变的。
查看String
的Javadoc,可以看到
[…字符串对象是 [...].
这意味着concat(String)
不会改变String
本身,而是构建一个新的String
。
StringBuilder
s是可变的。通过调用append(CharSequence)
,对象本身发生了变化。
由于String
是不可变的,因此String#concat
不会修改原来的String实例,它只返回一个新的String
,而原来的不修改,而StringBuilder
是可变的,变化反映在作为参数传递的StringBuilder
实例中。
好的,speak
方法在做什么?
首先,
name.concat("4");
创建一个新的对象,它等于name
,与"4"
连接。
那么,这行
name = name.concat(4);
重新定义本地 (speak
方法)变量name
。
然后用
返回对新值的引用return name;
因此,在方法中传递的原始变量没有被修改,但是方法返回修改后的值。
在test
方法中,您实际上修改变量而不修改引用(StringBuilder
类是可变的,因此如果该类型可以修改,则为变量)。
然后我们可以看到另一个问题:为什么StringBuilder.append
返回值,在那里它看起来是多余的。这个问题的答案在于"构建器"模式的描述,它是实现修改方法的常用方式。参见wikipedia上的Builder模式。
String
在java中不可变。只要在name上调用concat
方法。一个新的字符串被创建,当你在System.out.println(name)
中使用旧的引用时,如果你想使用修改的字符串,你应该显式地返回引用。而StringBuilder
是可变的,它总是返回相同的引用。
当您调用speak(name)
时,它会计算新值,但会丢弃它。
如果用
代替name = speak(name);
结果将是你所期望的。
对于StringBuilder
,您传递的对象是可变的:所以
names.append(names);
改变当前对象的状态(它还返回对同一对象的引用,这只是为了方便您编写names.append(...).append(...)
等代码)。因此,在StringBuilder
的情况下,当您调用该方法时引用的对象实际上已经更改,因此您可以看到更改。
在你的方法speak
中,concat
方法返回一个新的String,它被调用的原始对象是不变的(字符串是不可变的)。记录:
如果参数字符串的长度是
0
,则返回这个String
对象。否则,返回一个String
对象,该对象表示一个字符序列,该字符序列是由该String
对象表示的字符序列与参数字符串表示的字符序列的连接。
调用name.concat("4")
相当于调用name + "4"
。
在你的test
方法中,append
方法修改StringBuilder
的内容。记录:
StringBuilder
的主要操作是append
和insert
方法,它们是重载的,可以接受任何类型的数据。它们都有效地将给定的数据转换为字符串,然后将该字符串的字符追加或插入到字符串构造器中。append
方法总是在构造器的末尾添加这些字符;insert
方法在指定的点添加字符。
在你的主方法中,name
和names
仍然是与方法调用之前相同的对象,但是name
的内容没有变化,因为字符串是不可变的,而names
的内容已经改变了。
如果您使用了两个方法的返回值,那么您将得到您期望的结果。
首先,String
是Java中的不可变类。不可变类就是不能修改其实例的类。实例中的所有信息在创建实例时初始化,不能修改。
第二,在java中参数是按值发送的,而不是按引用发送的。
在你的方法'test'中,你不需要names = names.append("4")
,而names.append("4")
就足够了。
如果你检查java文档中的String object,你会看到那里的大多数方法,包括concat,都会生成一个新的String。
所以在输出Sam4也为字符串,你将需要在主方法有这个name = speak(name)
String
String是不可变的(一旦创建就不能更改)对象。的作为String类型创建的对象存储在常量字符串池中。Java中的每个不可变对象都是线程安全的,这意味着String也是也线程安全。字符串不能被两个线程使用同时进行。字符串一旦被赋值就不能更改。
String demo = " hello ";//以上对象存储在常量中不能修改字符串池及其值
演示="再见";//在常量池和中创建新的"Bye"字符串由demo变量引用//"hello"字符串仍然存在于字符串常量池中,其值不会被覆盖,但我们丢失对"hello"字符串的引用
StringBuilder
StringBuilder与StringBuffer相同,即它存储对象,它也可以被修改。主要区别StringBuffer和StringBuilder之间的区别在于StringBuilder是也不是线程安全的。StringBuilder很快,因为它不是线程安全的.
查看更多详细信息
结论:
您不需要再次将值重新分配给StringBuilder
,因为它已经是一个引用试验方法应为
public static void test(StringBuilder names) {
names.append("4");
}
但是说话应该是
String name = "Sam";
name = speak(name);