Java如何存储字符串以及子字符串如何在内部工作?

class StringTesting { public static void main(String args[]) { String str = "abcd"; String str1 = new String("abcd"); String str2 = str.substring(0,2); String str3 = str.substring(0,2); String str4 = str.substring(0,str.length()); String str5 = str1.substring(0,2); String str6 = str1.substring(0,2); String str7 = str1.substring(0,str1.length()); System.out.println(str2 == str3); System.out.println(str == str4); System.out.println(str5 == str6); System.out.println(str1 == str7); } } 

这是我在java 1.6.0_27上得到的输出:

 false true false true 

有人可以解释输出。 我知道Java区分存储在堆中的String和存储在String“common pool”中的String(可以是interned)。 在内部,他们的表现如何不同。 它是如何改变子串算法的。 请在适当的地方引用书籍/文章/博客等。

看评论:

  String str = "abcd"; // new String LITERAL which is interned in the pool String str1 = new String("abcd"); // new String, not interned: str1 != str String str2 = str.substring(0,2); // new String which is a view on str String str3 = str.substring(0,2); // same: str3 != str2 String str7 = str1.substring(0,str1.length()); // special case: str1 is returned 

笔记:

  • 从Java 7u6开始,substring返回一个新字符串而不是原始字符串上的视图(但这对该示例没有影响)
  • 调用str1.substring(0,str1.length());时的特殊情况str1.substring(0,str1.length()); – 见代码:

     public String substring(int beginIndex, int endIndex) { //some exception checking then return ((beginIndex == 0) && (endIndex == value.length)) ? this : new String(value, beginIndex, subLen); } 

编辑

什么是观点?

在Java 7u6之前,String基本上是一个char[] ,它包含带有偏移量和计数的字符串的字符(即字符串由从char[]offset位置开始的count字符组成)。

调用substring时,会创建一个具有相同char[]但不同偏移量/计数的新字符串,以有效地在原始字符串上创建视图。 (如上所述,当count = length和offset = 0时除外)。

从java 7u6开始,每次都会创建一个新的char[] ,因为字符串类中没有更多的countoffset字段。

公共池的存储位置在哪里?

这是特定于实现的。 在最近的版本中,池的位置实际上已移动。 在更新的版本中,它存储在堆上。

游泳池是如何管理的?

主要特征:

  • 字符串文字存储在池中
  • Interned字符串存储在池中( new String("abc").intern();
  • 当字符串S被中断时(因为它是文字或因为intern()被调用),如果有一个equals S的字符串,JVM将返回对池中字符串的引用(因此"abc" == "abc"应该总是返回true”。
  • 池中的字符串可以被垃圾收集(这意味着如果池中的字符串变满,可能会在某个阶段从池中删除它)

String是不可变的Object。

String#subString – 创建一个新的String。 资源

在代码中它是[open jdk 6] –

  public String substring(int beginIndex, int endIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } if (endIndex > value.length) { throw new StringIndexOutOfBoundsException(endIndex); } int subLen = endIndex - beginIndex; if (subLen < 0) { throw new StringIndexOutOfBoundsException(subLen); } return ((beginIndex == 0) && (endIndex == value.length)) ? this : new String(value, beginIndex, subLen); }