字符串对象和堆

发布于 2024-12-07 23:22:36 字数 434 浏览 0 评论 0原文

我正在准备 SCJP 考试,我正在解决一组样题。

有一个问题的答案我不确定,希望这里有人能够帮助我解决这个问题。

这里有一个问题,

假设:

11. public String makinStrings() {
12.    String s = "Fred";
13.    s = s + "47";
14.    s = s.substring(2, 5);
15.    s = s.toUpperCase();
16.    return s.toString();
17. }

调用此方法时将创建多少个 String对象

A. 1
B. 2
C. 3
D. 4
E. 5
F. 6

预先感谢您提供的任何帮助。 我非常欣赏它。

I am studying for the SCJP exam and I have a sample set of questions that I am working through.

One questions answer I am unsure about and was hoping someone here might be able to help me put this question to bed.

Here is the question,

Given:

11. public String makinStrings() {
12.    String s = "Fred";
13.    s = s + "47";
14.    s = s.substring(2, 5);
15.    s = s.toUpperCase();
16.    return s.toString();
17. }

How many String objects will be created when this method is invoked?

A. 1
B. 2
C. 3
D. 4
E. 5
F. 6

Thank you in advance for any help offered.
I greatly appriciate it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

握住我的手 2024-12-14 23:22:36

让我们逐行浏览一下。

第 11 行

一个简单的开始,这里没有创建任何字符串。

第 12 行

我们将字符串 "Fred" 分配给 s。虽然看起来这里创建了一个String,但是这个字符串会存在于常量池中。 JVMS 部分 2.17.6 创建新类实例保证字符串文字的对象最迟在加载周围的类时创建,根据定义,这是在调用方法之前。因此这一行没有创建新的字符串对象。

第 13 行

引用了文字字符串 "47",该字符串同样是静态创建的(如上所述)。不过,还需要调用 + 运算符,该运算符将创建一个新的 String 以保存连接的结果。这就是创建的第一个字符串。

第 14 行

substring 方法确实创建了一个新字符串。它与其父级共享底层字符数组 - 因此几乎不占用任何额外的内存 - 但由于字符串是不可变的,因此每个不同的字符串表示形式都需要不同的 String 对象。 (这可能是一个陷阱 - 我的第一个本能反应是“啊,由子字符串创建的字符串很特殊”,但当然它仍然需要创建一个新对象)。

第 15 行

如上所述 - 大写表示不同,因此必须创建一个新的字符串来保存结果。

第 16 行

Strings 覆盖 toString() 方法以简单地返回此 - 因此不会创建其他字符串。

门上的分数

据我统计,在此方法期间创建了三个 String 对象(其中两个对象共享相同的底层字符数组,并且两个预先存在的对象被字符串文字引用)。

Let's go through it line by line.

Line 11

An easy start, no strings created here.

Line 12

We're assigning the String "Fred" to s. Although it looks like a String is created here, this string will live in the constant pool. The JVMS section 2.17.6 Creation of New Class Instances guarantees that the objects for string literals will at latest be created when the surrounding class is loaded, which by definition is before the method is invoked. So no new string objects are created on this line.

Line 13

The literal string "47" is referenced, which again will have been created statically (as above). However there's also the invocation of the + operator, which will create a new String in order to hold the result of the concatenation. So that's the first string created.

Line 14

The substring method does indeed create a new String. It shares the underlying character array with its parent - and so takes up hardly any extra memory - but since Strings are immutable, each different string representation requires a different String object. (This is probably a gotcha - my first instinctive response was "ah, string created by substring are special" but of course it still has to create a new object).

Line 15

As above - the uppercase representation is different, so a new String must be created to hold the result.

Line 16

Strings override the toString() method to simply return this - hence no additional String is created.

The scores on the doors

By my count that's three String objects created during this method (with two of those objects sharing the same underlying character array, and with two pre-existing objects referenced for the string literals).

貪欢 2024-12-14 23:22:36

实际上,可以将整个方法变成一个常数。这是可能的,但编译器不允许这样做。因此,使用常量池中的 2 个创建了 3 个字符串。

  • Fred47
  • ed4(注意:使用与 Fred47 相同的支持 char[])
  • ED4

2 和 3 非常简单,因为编译器不允许优化此方法调用,但字符串已更改。 Sting.toString() 只返回 this,因此也没有新的 String。但是,让我们使用反汇编的字节代码来看看第 13 行(javap -c 是您的朋友):

public java.lang.String makinStrings();
  Code:
   0:   ldc #16; //String Fred
   2:   astore_1
   3:   new #18; //class java/lang/StringBuilder
   6:   dup
   7:   aload_1
   8:   invokestatic    #20; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
   11:  invokespecial   #26; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
   14:  ldc #29; //String 47
   16:  invokevirtual   #31; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   19:  invokevirtual   #35; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
       // SNIP
}

如您所见,“Fred”和“47”是从常量池加载的(ldc)来填充最终将成为字符串的 StringBuilder (StringBuilder.toString())。

这样,每个方法调用就会有 2 个常量字符串加上 3 个新创建的字符串。

Actually, it would be possible to make the whole method into a single constant. It's possible, but the compiler isn't allowed to do so. Hence, there are 3 Strings created using 2 from the constant pool.

  • Fred47
  • ed4 (note: using same backing char[] as Fred47 though)
  • ED4

2 and 3 are pretty easy as the compiler isn't allowed to optimize away this method invocations but the String is changed. Sting.toString() only returns this, so no new String either. But let's have a look on line 13 using disassembled byte code (javap -c is your friend here):

public java.lang.String makinStrings();
  Code:
   0:   ldc #16; //String Fred
   2:   astore_1
   3:   new #18; //class java/lang/StringBuilder
   6:   dup
   7:   aload_1
   8:   invokestatic    #20; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
   11:  invokespecial   #26; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
   14:  ldc #29; //String 47
   16:  invokevirtual   #31; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   19:  invokevirtual   #35; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
       // SNIP
}

As you see, "Fred" and "47" are loaded from the constant pool (ldc) to populate a StringBuilder that will finally become a String (StringBuilder.toString()).

So that makes 2 constant Strings plus 3 newly created Strings per method invocation.

乞讨 2024-12-14 23:22:36

我想说的是第 3 行:第 12、13 和 15 行。

第 14 行(子字符串)没有创建新对象的原因是 String 的内部工作方式。由于需要对子字符串进行优化(一切,包括编译器,都依赖于子字符串),String类有两个指向字符串开头和结尾的指针。执行子字符串只会移动 this 指针,而不会将对象“复制”到新对象中。

I'd say 3: the ones at lines 12, 13 and 15.

The reason why the line 14 (substring) doesn't create a new object is because of the internal way String works. Due to necessary optimization of substring (everything, including compiler, rely on substring), the String class has two pointers to the start and end of the string. Doing a substring only moves this pointers, and does not "copy" the object into a new one.

囍笑 2024-12-14 23:22:36

它将创建 5 个字符串对象 string

是不可变类,因此对于每个新字符串它将创建一个对象。

示例

  1. public String makeinStrings() {
    1. 字符串 s = "弗雷德"; (这一行创建 1--- Fred 字符串)
    2. s = s + "47"; (此行创建 2- 47 字符串 + 3- Fred47)
    3. s = s.substring(2, 5); (此行创建 4-ed4)
    4. s = s.toUpperCase();(此行创建 5-ED4)
    5. 返回 s.toString();

所以根据我的说法它会创建 5 个对象

it will create the 5 objects of string

string is immutable class so for every new string it will create an object.

example

  1. public String makinStrings() {
    1. String s = "Fred"; (this line create 1--- Fred string)
    2. s = s + "47"; (this line create 2- 47 string + 3- Fred47)
    3. s = s.substring(2, 5); (this line create 4-ed4)
    4. s = s.toUpperCase();(this line create 5-ED4)
    5. return s.toString();

So according to me it will create 5 object

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文