在Java中substring产生的结果不共享问题探讨,substring问题探讨
分享于 点击 30215 次 点评:198
在Java中substring产生的结果不共享问题探讨,substring问题探讨
这个问题其实涉及到 JVM 方法区中的 “常量池”概念。什么叫“常量池”呢?如果 Java 程序遇到字符串就 new 一个对象出来,其实是很浪费奢侈的行为。因此,JVM 针对字符串的获取做了优化,在方法区中新增一块“字符串常量池”
用来存放字符串常量,每次创建字符串常量时,首先判断字符串常量池是否存在该字符串,如果存在则返回该字符串的
引用实例;如果不存在,就实例化一个再放入池中。为啥能实现这个“常量池”的功能呢,其实一方面是字符串常量
是 final 修饰的无法被后续修改因此编译期便可以确定;二是常量池对每个对象在整个程序生命周期中都维护一个引用
来保证常量不会被GC回收。
有了上述概念我们先看第一个:
String a = "1";
String b = "1";
a == b 结果为 true
返回true的原因是因为上述 case 中的 a 和 b 对应的值 “1”是字符串常量,二者均是直接对常量池中“1”这个字
符串常量的引用,因此返回true。
substring 源码实现如下,如果 substring 的前后标截取的就是源字符串那就返回引用,如果不是就调用 new String(value, beginIndex, subLen)
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);
}
因此对于如下代码返回结果是 true:
public class Main{
public static void main(String[] args)
{
String a = "1234";
String b = a.substring(0,4);
System.out.println(a == b);
}
}
图1
但对于这种需要调用 new 的代码返回结果就是 false:
public class Main{
public static void main(String[] args)
{
String a = "1234";
String b = "123";
String c = a.substring(0,3);
System.out.println(b == c);
}
}
图2
因为当使用 new 方法创建对象时不会去常量池寻找该值是否已存在,只要你用了 new 那么结果都会实例化一个新的对象出来(这个对象在堆上,其值可能是引用常量池中已存在的常量),所以 substring 相当于创建了两个新的对象,
返回的引用自然是不同的。
如果不想担心这些问题,对字符串直接使用 equals 比较是最方便的。因为 equals 的实现中是先比较引用、再是类
型(instance of)、再是长度、再是挨个比较字符。
相关文章
- 暂无相关文章
用户点评