字符串常量池
常量池存放字面量和符号引用,或者直接引用
intern方法,它的 作用 是 如果 字符串 常量 池 中 已经 包含 一个 等于 此 String 对象 的 字符串, 则 返回 代表 池 中 这个 字符串 的 String 对象 的 引用; 否则, 会 将此 String 对象 包含 的 字符串 添加 到 常量 池 中, 并且 返回 此 String 对象 的 引用。也就是说常量池里还是字面量
String b;
String a=new String(b="ss");
String intern = a.intern();
//true
System.out.println(b==intern);
//false
System.out.println(a==intern);
其实看这段代码就明白了,new String创建了俩个堆对象,看string那个String参数的构造方法上就已经写明了,就是复制那个string参数再弄一份副本,所以其实"ss"这个字面量已经进入常量池了,而常量池里就是第一次创建的堆对象的引用,而后面new,也就是再New一份实例出来了而已,
String str1 = new StringBuilder("计算机"). append("软件"). toString();
System. out. println( str1. intern() == str1);
String str2 = new StringBuilder("ja"). append("va"). toString();
System. out. println( str2. intern() == str2);
这段 代码 在 JDK 6 中 运行, 会 得到 两个 false, 而在 JDK 7 中 运行, 会 得到 一个 true 和 一个 false。 产生 差异 的 原因 是, 在 JDK 6 中, intern() 方法 会把 首次 遇到 的 字符串 实例 复制 到 永久 代 的 字符串 常量 池 中 存储, 返回 的 也是 永久 代 里面 这个 字符串 实例 的 引用, 而由 StringBuilder 创建 的 字符串 对象 实例 在 Java 堆 上, 所以 必然 不可能 是 同一个 引用, 结果 将 返回 false。 而 JDK 7( 以及 部分 其他 虚拟 机, 例如 JRockit) 的 intern() 方法 实现 就不 需要 再 拷贝 字符串 的 实例 到 永久 代 了, 既然 字符串 常量 池 已经 移到 Java 堆 中, 那 只需 要在 常量 池 里 记录 一下 首次 出现 的 实例 引用 即可, 因此 intern()返回 的 引用 和 由 StringBuilder 创建 的 那个 字符串 实例 就是 同一个。 而对 str2 比较 返回 false, 这是 因为“ java”这个 字符 串在 执行 StringBuilder. toString() 之前 就 已经 在加载 sun. misc. Version 这个 类 的 时候 进入 常量 池 的。所以 字符串 常量 池 中 已经 有 它的 引用, 不符合 intern() 方法 要求“ 首次 遇到” 的 原则,“ 计算机 软件” 这个 字符串 则是 首次 出现 的, 因此 结果 返回 true。
字面量相加
String a=“1”+“2”+“3”+“4”;
会被编译器优化为一个String a="1234"直接放入字符串常量池中
字符串相加
String b=new String(“he”)+new String(“llo”);
其实是使用的StringBuilder.append最后再toString,但是toString不会放入字符串变量池,如果再调用b.intern()才会放入此对象放入字符串常量池中,然后就会发现,字符串常量池里就是存放的b的引用地址
String b=new String("he")+new String("llo");
String bIntern = b.intern();
String b1="hello";
//true
System.out.println(b==bIntern);
//true
System.out.println(bIntern==b1);
//true
System.out.println(b==b1);
b1就是直接拿的b放入字符串常量池的那个对象
只是个人的一些想法,欢迎大家指正