9
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区分存储在堆中的字符串和存储在字符串“公共池”(可以被实习)中的字符串。在内部,它们的表示方式有何不同。它如何改变子字符串算法。请在适当的地方引用书籍/文章/博客等。

4

2 回答 2

22

见评论:

    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 开始,子字符串返回一个新字符串而不是原始字符串的视图(但这对于该示例没有影响)
  • 致电时的特殊情况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 基本上是 a char[],它包含字符串的字符以及偏移量和计数(即字符串由count从 中的offset位置开始的字符组成char[])。

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

从java 7u6开始,char[]每次都新建一个,因为string类中没有morecountoffset字段。

公共池具体存储在哪里?

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

游泳池是如何管理的?

主要特征:

  • 字符串文字存储在池中
  • 内部字符串存储在池中 ( new String("abc").intern();)
  • 当一个字符串S被保留时(因为它是一个字面量或者因为intern()被调用),JVM 将返回一个对池中字符串的引用,如果有一个是equals指向的S(因此"abc" == "abc"应该总是返回 true)。
  • 池中的字符串可以被垃圾回收(这意味着如果某个阶段的字符串已满,则可能会从池中删除它)
于 2013-01-07T10:02:36.473 回答
2

String是不可变的对象。

String#subString- 创建一个新字符串。来源

在代码中是 [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);
}
于 2013-01-07T10:02:05.467 回答