String 与 StringBuffer 返回值

String vs StringBuffer returned value

你能解释一下为什么在下面的代码中 StringStringBuffer 的处理方式不同,并且当值附加在 StringBuffer 中而不是字符串中时。

public class MyClass {
    
    public static void main(String args[]) {
        String str = new String("String Rohan ");
    StringBuffer strBfr = new StringBuffer("String Buffer Rohan "); 
        
        strUpdate(str);
        strBfrUpdate(strBfr);
        
        System.out.println(str);
        System.out.println(strBfr);
        
    }
    
    private static void strBfrUpdate(StringBuffer strBfr){
        strBfr.append("Kushwaha");
    }
    
    private static void  strUpdate(String str){
        str += "Kushwaha";
    }
}

输出如下:

String Rohan

String Buffer Rohan Kushwaha

在 strUpdate 方法中,您保留对名为 str:

的字符串的引用
private static void  strUpdate(String str){
    str += "Kushwaha";
}

当你写 str += "...";意思是:

    str = new String(str + "...");

此时 str 引用了新的 String,但仅在 strUpdate 方法中。不是 "taken back" 到 main.

在主要方法中

String str = new String("String Rohan ");

str 是指向 Java-JVM 堆内存中某个位置的引用(指针)。我们称这个地方为 A

str->A

private static void  strUpdate(String str){
    //str here is still pointing to A, but technically this parameter
    //is a copy of the reference of the str pointer in the main-method
    //pointing to the same place in the heap
    //str->A
    str += "Kushwaha";
    // this line is short for str = str + "Kushwaha"
    //what happens here that you create a new String-Object in the heap (B)
    //and assigne the new value "String Rohan Kushwaha" to the new pointer
    //if you print it out now (within this method) you get what you would 
    //expect
    System.out.println(str);
    //will result in "String Rohan Kushwaha"
}

但是 main 方法的 str 指针仍然指向堆中的位置 A,其中仍然只有 "String Rohan"。因此,一旦您离开方法 strUpdate(...) 的范围,复制的指针(重新分配给位置 B)将被删除。

希望这对您有所帮助...

我想这是一些有助于您理解的信息

Is Java "pass-by-reference" or "pass-by-value"?

为了看清楚区别,identityHashCode见System#identityHashCode

package example;

public class MyClass {

     public static void main(String args[]) {
            String str = new String("String Rohan ");
        StringBuffer strBfr = new StringBuffer("String Buffer Rohan "); 

            System.out.println("--- String ---");
            System.out.println("Before update: " + System.identityHashCode(str));
            strUpdate(str);
            System.out.println("After update: " + System.identityHashCode(str));
            System.out.println("--- StringBuffer ---");
            System.out.println("Before String Buffer update: " + System.identityHashCode(strBfr));
            strBfrUpdate(strBfr);
            System.out.println("After String Buffer update: " + System.identityHashCode(strBfr));

            System.out.println("--- Final output ---");
            System.out.println(str);
            System.out.println(strBfr);

        }

        private static void strBfrUpdate(StringBuffer strBfr){
            System.out.println("StringBuffer parameter: " + System.identityHashCode(strBfr));
            strBfr.append("Kushwaha");
            System.out.println("StringBuffer object modification: " + System.identityHashCode(strBfr));
        }

        private static void  strUpdate(String str){
            System.out.println("Parameter: " + System.identityHashCode(str));
            str += "Kushwaha";
            System.out.println("Modified (a new String, passed String instance remain same and each modification will produce new String instance): " + System.identityHashCode(str));      }
}

输出(你的会不同):

--- String ---
Before update: 390033781
Parameter: 390033781
Modified (a new String): 1177666623
After update: 390033781
--- StringBuffer ---
Before String Buffer update: 1833642009
StringBuffer parameter: 1833642009
StringBuffer object modification: 1833642009
After String Buffer update: 1833642009
--- Final output ---
String Rohan 
String Buffer Rohan Kushwaha

也看看@Rainer提到的Java "pass-by-reference" or "pass-by-value"

当我们修改现有字符串时,将在字符串池中创建一个新的字符串实例,并且字符串引用变量将指向新文字。将删除对旧文字的引用。

在您的例子中,为字符串创建了两个文字。 一个在 main 方法中,另一个在 strUpdate 方法中。 主要方法中的引用变量 str 指向“Rohan”(您实际上在输出中打印) 而 strUpdate 方法中的引用变量 str 指向“Rohan Kushwaha”(如果你在这个方法中打印,你将得到“Rohan Kushwaha”)

但是当我们使用 StringBuffer 作为方法的参数时,我们实际上是在发送对象引用。当我们将对象作为引用传递时,修改对调用方法也是可见的。因此我们看到字符串 "Rohan Kushwaha" 缓冲区

正如 Shriram 在他的评论中所说:字符串在 Java 中是 不可变的 ,一旦创建它们就 不能 被改变.这个问题已经被问过很多很多次了(例如here)。

字符串是不可变的(一旦创建就不能更改)object.Every Java 中的不可变对象是线程安全的,这意味着字符串也是线程安全的。字符串不能同时被两个线程使用。

例如,

String  demo= " hello Rohan " ;
// The above object is stored in constant string pool and its value can not be modified.

demo="Bye Rohan" ;     //new "Bye Rohan" string is created in constant pool and referenced by the demo variable            
 // "hello Rohan " string still exists in string constant pool and its value is not overrided but we lost reference to the  "hello Roahn" string  

另一方面,

StringBuffer 是可变的,意味着可以改变对象的值。通过 StringBuffer 创建的对象存储在堆中。 StringBuffer 具有与 StringBuilder 相同的方法,但 StringBuffer 中的每个方法都是同步的,即 StringBuffer 是线程安全的。

为了帮助你更清楚地理解下面link有一个很好的例子 http://www.javatpoint.com/difference-between-string-and-stringbuffer 这表明 String 中的 HasCode 不同,但对于 String 缓冲区,HashCode 是相同的。 在你的情况下,因为 String 是不可变的

strUpdate() 方法的连接值未添加到主字符串中。所以它保持不变。
希望这能回答您的问题。