【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 .

回答

说下我的理解,欢迎拍砖

  • 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

}

先说一下我的答案: 我感觉是 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") 创建.

因此最终有三个对象创建了.

谢谢各位的回答,大概理解了,可惜我现在看不懂反编译的代码

我觉得,在创建StringBuffer对象的时候实际上在调用了其父类的AbstractStringBuilder的构造方法,父类有一个对象叫做char[] value数组对象,在StringBuffer调用带参数构造方法的时候实际上还将value这个数组对象给创建了,这个数组存储了字符串的每个字符,所以创建的对象不止6个对象,附上图【java】以下创建了几个对象【java】以下创建了几个对象

常量池的字符串常量也算对象啊,不然怎么能调用方法 "a".equals()

以上是 【java】以下创建了几个对象 的全部内容, 来源链接: utcz.com/a/73004.html

回到顶部