38

我的朋友给我发了一个他在 Java 认证模拟考试中看到的关于字符串对象的问题:

String makeStrings(){
    String s = "HI";
    s = s + "5";
    s = s.substring(0,1);
    s = s.toLowerCase();
    return s.toString();
}

调用此方法时将创建多少个字符串对象?考试给出的正确答案是 3。但我认为是 5。

  1. “你好”
  2. “5”
  3. “HI5”
  4. “H”
  5. “H”

我错了吗?

4

3 回答 3

46
String makeStrings() {
    String s = "HI";           //String literal
    s = s + "5";               //concatenation creates new String object (1)
    s = s.substring(0,1);      //creates new String object (2)
    s = s.toLowerCase();       //creates new String object (3)
    return s.toString();       //returns already defined String
}

关于串联,在创建新字符串时,JVM使用StringBuilder,即:

s = new StringBuilder(s).append("5").toString(); 

toString()对于 aStringBuilder是:

public String toString() {
    return new String(value, 0, count); //so a new String is created
}

substring除非整个String被索引,否则创建一个新的 String 对象:

public String substring(int beginIndex, int endIndex) {
    if (beginIndex < 0) {
        throw new StringIndexOutOfBoundsException(beginIndex);
    }
    if (endIndex > count) {
        throw new StringIndexOutOfBoundsException(endIndex);
    }
    if (beginIndex > endIndex) {
        throw new StringIndexOutOfBoundsException(endIndex - beginIndex)
    }

    return ((beginIndex == 0) && (endIndex == count)) ? this :
           new String(offset + beginIndex, endIndex - beginIndex, value);
}

toString()创建新字符串:

public String toString()
{
   return this;
}

toLowerCase()是一个相当长的方法,但只要说如果String不是全小写,它就会返回 a就足够了。new String

鉴于提供的答案是3,正如 Jon Skeet 建议的那样,我们可以假设两个字符串文字都已经在字符串池中。有关何时将字符串添加到池中的更多信息,请参阅有关 Java 的字符串池的问题

于 2013-07-27T13:21:09.493 回答
13

s = s + "5";

被翻译成:

String s = new StringBuilder(s).append("5").toString();

现在,创建了一个对象。


s = s.substring(0,1); 

创建一个新字符串。


s = s.toLowerCase();

创建一个新对象。


return s.toString(); 

不创建字符串,它返回一个已经创建的字符串。

于 2013-07-27T13:26:50.503 回答
9

其他一些答案确实有意义,但是字符串文字呢?

String s = "HI";

对于字符串文字,当 .java 文件编译为 .class 文件时,任何字符串文字都以特殊方式注明,就像所有常量一样。当一个类被加载(注意加载发生在初始化之前)时,JVM 会遍历该类的代码并查找字符串文字。

当它找到一个时,它会检查是否已经从堆中引用了等效的字符串。如果没有,它会在堆上创建一个 String 实例,并将对该对象的引用存储在常量表中

一旦对该字符串对象进行了引用,整个程序中对该字符串文字的任何引用都将简单地替换为对字符串文字池中引用的对象的引用。

因此应该有四个 Java 对象,尽管当一次又一次地调用相同的方法时,将只有三个对象,因为在应用程序中,字符串文字池包含文字“HI”。

此外,有关在执行上述方法块时为什么会创建新对象的更多信息,我们还可以检查不同字符串的不同哈希码(String不可变)。

  public static void main(String[] args)
  {
      NumberOfString str = new NumberOfString();
      String s = str.makeStrings();
      System.out.println(s.hashCode());
  }

  public String makeStrings()
  {
      String s = "HI";
      System.out.println(s.hashCode());
      s = s + "5";
      System.out.println(s.hashCode());
      s = s.substring(0, 1);
      System.out.println(s.hashCode());
      s = s.toLowerCase();
      System.out.println(s.hashCode());
      return s.toString();
  }

您会得到以下输出:

2305
71508
72
104
104

在上面的例子中,我们是否应该不计入 String 字面量对象?

于 2013-07-29T05:36:16.770 回答