搜尋

首頁  >  問答  >  主體

java - 以下创建了几个对象

String a,b,c;
a = "a";
b = "b";
a = a+b;
StringBuffer d = new StringBuffer("abc");
d = d.append("567");

我觉得是6个,"a" "b" "ab" "abc" "567" 还有d.

PHP中文网PHP中文网2767 天前811

全部回覆(3)我來回復

  • 高洛峰

    高洛峰2017-04-18 10:25:06

    說下我的理解,歡迎拍磚

    • a = "a"; 編譯時字串"a"放入常數池,不會在堆上建立物件

    • b = "b"; 同理

    • a = a + b;new 一個StringBuilder對象,append(a), append(b), 最後返回tostring()給a.

    • StringBuffer d = new StringBuffer("abc"); 這裡肯定建立一個對象,同時"abc"進入常數池

    • d = d.append("567"); StringBuffer 使用一個char數組保存字串,append會往數組裡面加入"567",如果數組容量不夠,會進行擴充,預設大小是16 + "abc"的長度= 19,"abc567"長度為6, 3 + 3 < 19所以不會造成擴容。

    • 還有一點,StringBuffer 和 StringBuilder是繼承了AbstractStringBuilder的,可能會造成父類別的建立。

    這是反編譯出來的程式碼:

    /**
     *
     * 源代码
     *public class TestString {
     *    public static void main(String args[]) {
     *        String a = "a";
     *        String b = "b";
     *        String c = a + b;
     *    }
     *}
     *
     */
    
    Compiled from "TestString.java"
    public class TestString {
        public TestString();
    Code:
    0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return
    
           public static void main(java.lang.String[]);
    Code:
           0: ldc           #2                  // String a
           2: astore_1
           3: ldc           #3                  // String b
           5: astore_2
           6: new           #4                  // class java/lang/StringBuilder
           9: dup
           10: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
           13: aload_1
           14: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    17: aload_2
            18: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    21: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
    24: astore_3
            25: return
    }
    

    回覆
    0
  • 迷茫

    迷茫2017-04-18 10:25:06

    先說一下我的答案: 我感覺是 3 個.


    首先, 明確一下 创建对象 的具体含义. 按我的理解, 如果字符串是 字符常量, 那么这个字符串对象是在编译时候确定好的, 它是存放在常量池中的, 因此就不算是创建了一个字符串对象, 而如果有 String b = new String("abc") 之类的操作, 那么可以认为是创建了字符串对象, 并与变量 b 關聯.

    根據上面的定義, 那麼有: "a", "b", "abc", "567" 都是常數, 放在常量池中的, 因此就不算是創建對象了.

    那麼來看一下程式碼:
    原始碼:

    1: String a,b,c;
    2: a = "a";
    3: b = "b";
    4: a = a+b;
    5: StringBuffer d = new StringBuffer("abc");
    6: d = d.append("567");

    為了方便起見, 我手動給每一行編號了.
    再來看一下對應的字節碼:

    Code:
      stack=3, locals=5, args_size=1
         0: ldc           #2                  // String a
         2: astore_1
         3: ldc           #3                  // String b
         5: astore_2
         6: new           #4                  // class java/lang/StringBuilder
         9: dup
        10: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
        13: aload_1
        14: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        17: aload_2
        18: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        21: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        24: astore_1
        25: new           #8                  // class java/lang/StringBuffer
        28: dup
        29: ldc           #9                  // String abc
        31: invokespecial #10                 // Method java/lang/StringBuffer."<init>":(Ljava/lang/String;)V
        34: astore        4
        36: aload         4
        38: ldc           #11                 // String 567
        40: invokevirtual #12                 // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
        43: astore        4
        45: return

    由字節碼可以看出, 源碼的第四行 a = a+b 翻譯為如下程式碼:

    StringBuilder builder = new StringBuilder();
    builder.append(a);
    builder.append(b);
    a = builder.toString();

    那麼這裡就新建了一個物件 new StringBuilder(), 接着调用 builder.toString() 方法, 它原始碼如下:

    @Override
    public String toString() {
        // Create a copy, don't share the array
        return new String(value, 0, count);
    }

    於是 builder.toString() 方法创建了一个 String 对象, 因此目前我们已经创建了 两个对象 了.

    接著第五行 StringBuffer d = new StringBuffer("abc") 毫无疑问是 创建了对象 StringBuffer, 于是我们就有 三个对象 了. 有一点需要注意的是 StringBuffer d 从始至终都没有调用 toString 方法, 因此就不會有多餘的 String 創建出來.


    總結:

    • "a": 字串常數, 不算創建物件

    • "b": 字串常數, 不算創建物件

    • builder 物件: 在執行 a = a+b 時建立.

    • "ab": 由 StringBuilder.toString() 創建.

    • "abc": 字串常數, 不算創建物件

    • "567": 字串常數, 不算創建物件

    • d: 透過 new StringBuffer("abc") 創建.

    因此最終有三個物件創建了.

    回覆
    0
  • 阿神

    阿神2017-04-18 10:25:06

    謝謝各位的回答,大概理解了,可惜我現在看不懂反編譯的程式碼

    回覆
    0
  • 取消回覆