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[]
,因为字符串类中没有更多的count
或offset
字段。
公共池的存储位置在哪里?
这是特定于实现的。 在最近的版本中,池的位置实际上已移动。 在更新的版本中,它存储在堆上。
游泳池是如何管理的?
主要特征:
- 字符串文字存储在池中
- 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); }