关于Java中的字符串不变性

关于Java中的字符串不变性,java,string,Java,String,首先,我知道java中的字符串是不可变的 我有一个关于字符串不变性的问题: public static void stringReplace (String text) { text = text.replace ('j' , 'c'); /* Line 5 */ } public static void bufferReplace (StringBuffer text) { text = text.append ("c"); /* Line 9 */ } publi

首先,我知道java中的字符串是不可变的

我有一个关于字符串不变性的问题:

public static void stringReplace (String text) 
{
    text = text.replace ('j' , 'c'); /* Line 5 */
} 
public static void bufferReplace (StringBuffer text) 
{ 
    text = text.append ("c");  /* Line 9 */
} 
public static void main (String args[]) 
{ 
    String textString = new String ("java"); 
    StringBuffer textBuffer = new StringBuffer ("java"); /* Line 14 */
    stringReplace(textString); 
    bufferReplace(textBuffer); 
    System.out.println (textString + textBuffer); //Prints javajavac
} 
但如果我们写下以下内容:

public static void bufferReplace (StringBuffer text) 
{ 
    text = text.append ("c");  /* Line 9 */
} 
public static void main (String args[]) 
{ 
    String textString = new String ("java"); 
    StringBuffer textBuffer = new StringBuffer ("java"); /* Line 14 */
    textString = textString.replace ('j' , 'c');
    bufferReplace(textBuffer); 
    System.out.println (textString + textBuffer); //Prints cavajavac
} 
问题是,我希望第一个示例打印的内容与第二个相同。原因是当我们将
textString
传递给函数时,我们实际上传递了对
textString
的引用。现在在函数体中,另一个字符串由
text.replace('j','c')
生成,我们将该字符串的引用分配给传入的字符串。 在第二个示例中,我只为
textString.replace('j','c')生成的字符串分配了一个引用
testString
。为什么会有如此大的差异


因此,结果必须相同。怎么了?

在第二个示例中
textString=textString.replace('j','c')
发生在main方法中,因此
textString
变量被分配一个新的
String
,并且在打印输出时可以看到新的
String
的值

在第一个示例中,这不会发生,因为对
stringReplace
方法的调用无法更改传递给它的
String
引用。因此,您看到的输出就好像从未调用过
stringReplace(textString)


这一切归结为Java是一种传递值语言。无法更改传递给方法的对象引用,因为该引用是按值传递的。如果String不是不可变的,您可以通过调用更改其状态的String方法(如果存在此类方法)来更改传递给该方法的String实例,但您仍然无法将新的String引用分配给该方法的参数,并且无法在该方法的调用方中看到它的反映。

。如果您提供对JLS的规范性引用,那就更好了。当调用方法或构造函数(§15.12)时,实际参数表达式的值在执行方法或构造函数主体之前初始化新创建的参数变量(每个声明类型)。Java是按值传递的。@St.Antario您没有改变传递给该方法的StringBuffer引用。如果尝试为传递给该方法的变量分配新的StringBuffer,结果将与接受字符串的方法相同。StringBuffer的不同之处在于,您可以在方法内变异引用引用的对象。因为text.append(“c”)修改StringBuffer的内部状态,而text.replace('j','c')返回文本字符串的副本,其中j已被c.No替换。创建对StringBuilder的引用的副本并将其传递给该方法。因此,为引用指定新值不会更改原始值,但由于两个引用(原始和副本)都指向同一个对象,因此更改方法中对象的状态也会影响调用方法中的对象:只涉及一个对象。顺便说一句。如果不需要同步,请使用StringBuilder而不是StringBuffer。@jakub.petr为什么它如此重要?@St.Antario,因为从这个角度来看,
StringBuffer
StringBuilder
慢得多,任何类/对象都可能被认为是不可变的。