【问题标题】:String vs StringBuffer returned value [duplicate]String vs StringBuffer返回值[重复]
【发布时间】:2016-05-12 09:43:03
【问题描述】:

您能否解释一下为什么在下面的代码中 StringStringBuffer 会被区别对待,以及在 StringBuffer 中附加值而不是在 String 中附加值时。

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";
    }
}

输出如下:

字符串罗汉

字符串缓冲区 Rohan Kushwaha

【问题讨论】:

  • 因为 String 是不可变的,而 stringbuffer 是可变的。

标签: java string stringbuffer


【解决方案1】:

在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-method 的 str 指针仍然指向堆中的位置 A,其中仍然只有“String Rohan”。因此,一旦您离开 strUpdate(...) 方法的范围,复制的指针(重新分配给位置 B)就会被删除。

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

我想这是一些有助于您理解的有用输入

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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

      只是为了看清楚区别,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"

      【讨论】:

        【解决方案4】:

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

        例如,

        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 是线程安全的。

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

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

        【讨论】:

          【解决方案5】:

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

          【讨论】:

            【解决方案6】:

            在 strUpdate 方法中,您保留对名为 str 的字符串的引用:

            private static void  strUpdate(String str){
                str += "Kushwaha";
            }
            

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

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

            此时 str 引用了新的 String,但仅在 strUpdate 方法中。它没有被“收回”到 main 中。

            【讨论】:

            • 为什么我得到-1?我写的和得到 +1 的答案有什么区别?
            猜你喜欢
            • 2015-12-13
            • 2014-07-10
            • 2016-11-06
            • 2015-09-02
            • 2012-09-09
            • 2015-10-01
            • 2012-02-18
            • 2013-07-27
            • 2011-04-16
            相关资源
            最近更新 更多