public static void main(String[] args)
{
StringBuilder sb = new StringBuilder("hello, world!");
System.out.println(sb);
foo(sb);
System.out.println(sb);
}
public static void foo(StringBuilder str)
{
str.delete(0, str.length());
str.append("String has been modified");
}
另一种选择是使用String作为范围变量创建一个类(非常不鼓励),如下所示:
class MyString
{
public String value;
}
public static void main(String[] args)
{
MyString ms = new MyString();
ms.value = "Hello, World!";
}
public static void foo(MyString str)
{
str.value = "String has been modified";
}
14 回答
你有三个选择:
从性能的角度来看,StringBuilder通常是最佳选择 .
在Java中没有任何内容通过引用传递 . 一切都是 passed by value . 对象引用按值传递 . 另外字符串是 immutable . 因此,当您附加到传递的String时,您只需获得一个新的String . 您可以使用返回值,或者传递StringBuffer .
发生的事情是引用按值传递,即传递引用的副本 . java中没有任何内容通过引用传递,并且由于字符串是不可变的,因此该赋值创建了一个新的字符串对象,该引用的副本现在指向该对象 . 原始引用仍指向空字符串 .
这对任何对象都是相同的,即在方法中将其设置为新值 . 下面的例子只是让事情变得更加明显,但连接一个字符串实际上是一回事 .
java.lang.String是不可变的 .
我讨厌粘贴URL,但如果你在java-land中,https://docs.oracle.com/javase/10/docs/api/java/lang/String.html对于你阅读和理解是必不可少的 .
对象通过引用传递,基元通过值传递 .
String不是原始的,它是一个对象,它是object的特例 .
这是为了节省内存 . 在JVM中,有一个字符串池 . 对于创建的每个字符串,JVM将尝试查看字符串池中是否存在相同的字符串,如果已存在,则指向它 .
/ * OUTPUT * /
==正在检查内存地址(引用),.equals正在检查内容(值)
String是Java中的不可变对象 . 您可以使用StringBuilder类来完成您要完成的工作,如下所示:
另一种选择是使用String作为范围变量创建一个类(非常不鼓励),如下所示:
Java中的所有参数都是按值传递的 . 将
String
传递给函数时,传递的值是对String对象的引用,但您无法修改该引用,并且基础String对象是不可变的 .分配
相当于:
也就是说,它(本地)将参数
zText
重新指定为新引用,该引用指向新的内存位置,其中包含zText
的原始内容,其中附加了"foo"
.原始对象未被修改,
main()
方法的局部变量zText
仍指向原始(空)字符串 .打印:
如果要修改字符串,可以使用
StringBuilder
或者使用一些容器(数组或AtomicReference
或自定义容器类)来为您提供额外级别的指针间接 . 或者,只需返回新值并指定它:打印:
这可能是一般情况下最类似Java的解决方案 - 请参阅Effective Java item "Favor immutability."
如上所述,
StringBuilder
通常会为您提供更好的性能 - 如果您有很多要做的事情,特别是在循环内,请使用StringBuilder
.但是如果可以的话,尝试传递不可变的
Strings
而不是可变的StringBuilders
- 您的代码将更容易阅读和更易于维护 . 考虑使用参数final
,并配置IDE以在将方法参数重新分配给新值时发出警告 .String是Java中的一个特殊类 . 它是线程保存,意思是“一旦创建了一个String实例,String实例的内容将永远不会改变” .
这是正在发生的事情
首先,Java编译器将获取zText String实例的值,然后创建一个新的String实例,其值为zText,附加“foo” . 所以你知道为什么zText指向的实例没有改变 . 这完全是一个新的例子 . 实际上,甚至String“foo”也是一个新的String实例 . 因此,对于这个语句,Java将创建两个String实例,一个是“foo”,另一个是zText的值附加“foo” . 规则很简单:String实例的值永远不会改变 .
对于方法fillString,您可以使用StringBuffer作为参数,或者您可以像这样更改它:
答案很简单 . 在java中,字符串是不可变的 . 因此它就像使用'final'修饰符(或C / C中的'const') . 所以,一旦分配,你就不能像你那样改变它 .
您可以更改字符串指向的值,但不能更改此字符串所在的实际值目前指点 .
IE浏览器 .
String s1 = "hey"
. 您可以使用s1 = "woah"
,并且's totally ok, but you can'实际上将字符串的基础值(在这种情况下:"hey")更改为使用plusEquals等分配的其他内容(即s1 += " whatup != "hey whatup"
) .为此,使用StringBuilder或StringBuffer类或其他可变容器,然后只需调用.toString()将对象转换回字符串 .
注意:字符串通常用作哈希键,因此这是它们不可变的部分原因 .
Java中的字符串是immutable .
这适用于StringBuffer
甚至更好地使用StringBuilder
字符串在java中是不可变的 . 您无法修改/更改现有的字符串文字/对象 .
String s =“Hello”; s = s“hi”;
这里先前的引用s被指向值“HelloHi”的新引用替换 .
但是,为了带来可变性,我们有StringBuilder和StringBuffer .
StringBuilder s = new StringBuilder(); s.append( “你好”);
这会将新值“Hi”附加到相同的引用 . //
到目前为止,Aaron Digulla有最好的答案 . 他的第二个选项的变体是使用commons lang库版本3的包装器或容器类MutableObject:
您保存容器类的声明 . 缺点是依赖于公共资源 . 但是lib有很多有用的功能,几乎任何我工作过的大项目都使用它 .
对于在java中通过引用传递对象(包括String),您可以将其作为周围适配器的成员传递 . 具有通用的解决方案在这里: