Java中有多less个string对象?

我的朋友给我一个问题,他在一个模拟考试中看到关于string对象的Javaauthentication:

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

调用此方法时将创build多less个string对象? 考试给出的正确答案是3,但是我认为是5。

  1. “HI”
  2. “5”
  3. “HI5”
  4. “H”
  5. “H”

我错了吗?

 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 } 

关于连接,当创build一个新的String时, JVM使用StringBuilder ,即:

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

toString()为一个StringBuilder是:

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

substring创build一个新的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()不会创build一个新的String:

 public String toString() { return this; } 

toLowerCase()是一个相当长的方法,但足以说,如果String 不是全部小写,它将返回一个new String

鉴于提供的答案是3 ,正如Jon Skeet所build议的那样,我们可以假定两个string字面值已经在string池中。 有关何时将string添加到池中的更多信息,请参阅有关Javastring池的问题 。

s = s + "5";

被翻译成:

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

现在,创build一个对象。


 s = s.substring(0,1); 

创build一个新的string。


 s = s.toLowerCase(); 

创build一个新的对象。


 return s.toString(); 

不会创build一个string,它会返回一个已经创build的string。

其他一些答案是有道理的,但是string呢?

 String s = "HI"; 

对于string文字,当一个.java文件被编译成一个.class文件时,任何string都以特殊的方式logging下来,就像所有的常量一样。 当一个类被加载时(注意加载发生在初始化之前),JVM通过类的代码并查找string文字。

当它find一个时,它会检查是否已经从堆中引用了等价的string。 如果不是,则在堆上创build一个String实例,并将该对象的引用存储在常量表中

一旦对该string对象进行了引用,则在整个程序中对该string文本的任何引用都将简单地replace为对string文字池引用的对象的引用。

因此,应该有四个Java对象,尽pipe当同一个方法被一次又一次地调用,那么只有三个对象,如应用程序中string文字池包含文字“HI”。

另外,关于为什么在执行上述方法块时创build新对象的更多信息,我们还可以检查不同string的哈希码( 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字面值对吗?