String 与 intern理解

来源:互联网 发布:高并发web架构 java 编辑:程序博客网 时间:2024/06/05 19:32

1.
public static void main(String[] args) {    String s = new String("abc");    System.out.println(s == s.intern());}
在这个代码中,首先创建的String对象是“abc”这个string字面量,然后才是new String 这个对象,为什么?因为在编译期,“abc”就已经存在.class中的常量池中,当类加载的时候,把它从.class中加载进来,在堆中首先创建了这个“abc”字面量的对象。当所有的类加载工作完成后才去执行代码指令。关于运行时常量池中的string,保存的是这个string对象的引用,而什么决定了它应该保存哪个对象的引用呢,像上面的代码,它保存的是s这个引用还是“abc”对象的引用呢?谁先创建出对象谁的引用就会放置在常量池中,所以常量池的引用就是“abc”对象的引用。

intern方法:调用这个方法的String对象的字面量在常量池中已经存在引用,就返回常量池的引用,否则就将这个对象的引用作为这个字面量的引用。上面的例子就是:s调用intern方法,JVM就去常量池看看是否有“abc”这个字面量的引用,有就返回这个引用,也就是“abc”这个对象的引用,所以上面的打印结果就是false;

2.
public static void main(String[] args) {    String s = new StringBuilder("game ").append("over").toString();    System.out.println(s == s.intern());}
2.这个例子中s的字面量为“game over”,而在常量池中只有“game ”和“over” 两个字面量的引用,所以当s调用intern方法的时候,JVM发现常量池没有“game over”字面量引用,所以将“game over”解释为s这个引用,所以打印结果为true

3.
public static void main(String[] args) {    String str = "game over";    String s = new StringBuilder("game ").append("over").toString();    System.out.println(s == s.intern());    System.out.println(str == s.intern());}
3.这个例子中在2.的例子最前面加了
String str = "game over";

那么当s调用intern返回的就是str这个引用,所以打印就是 false ,true

4.
public static void main(String[] args) {    String s = new StringBuilder("game over").toString();    System.out.println(s == s.intern());}
而4.这个例子1.这个例子是一样的,s调用返回的是“game over”这个对象的引用,当然是不等于s,所以打印结果为false

5.
public static void main(String[] args) {    String s = new StringBuilder("jav").append("a").toString();    System.out.println(s == s.intern());}
那么5.这个例子的结果又是什么?

结果是false,因为在

new StringBuilder("jav").append("a").toString();

这句代码执行之前,在常量池中已经长在“java”这个字面量对象的引用了,stackoverflow有这个问题的讨论,

At a guess, this class is used on startup to launch the programdocjar.com/html/api/com/sun/tools/jdi/… and on line 125 there is the String literal "java" – Peter Lawrey,程序运行时“java”字面量对象的引用就存在常量区,图片

6
public static void main(String[] args) {    String s = new StringBuilder("ja").append("va").toString();    System.out.println(s.intern() == "java");}
6这个例子是true ,Java语言说明中要求字符串字面量必须唯一,一样的字符串字面量必须为同一个String实例。所以“java“与intern返回的引用是同一个引用

7
public static void main(String[] args) {    String s = "abc";    String s1 = "abc";    String s2 = "abc";    System.out.println(s == s1);    System.out.println(s == s2);    System.out.println(s.intern() == s);    System.out.println(s1.intern() == s);    System.out.println(s2.intern() == s);}
打印的结果都是true,在常量区中存在的引用一直是”abc“,在堆中只创建了一个String对象(引用忽略)

8.
public static void main(String[] args) {    String s = "ab";    String s1 = "a" + "b";    System.out.println(s == s1);//true    String s2 = "c" + "d";    String s3 = new StringBuilder("c").append("d").toString();    System.out.println(s3 == s3.intern());//false    System.out.println(s2 == s3.intern());//true    String s4 = "efg" + "h";    String s5 = new StringBuilder("eg").append("f").toString();    System.out.println(s5.intern() == s5);//true}
java对”+“连接为优化后的值,javap查看

 String s4 = "efg" + "h";    String s5 = new StringBuilder("eg").append("f").toString();    System.out.println(s5.intern() == s5);//true
这段代码则证明了,”efg“在s5调用intern之前在常量池不存在它的引用,所以
s5.intern() == s5);为true

9.
public static void main(String[] args) {    String s = "a";    String s1 = s + "b";    String s2 = "ab";    System.out.println(s1 ==s2);    final String s3 = "c";    String s4 = s3 + "d";    String s5 = "cd";    System.out.println(s4 == s5);}
JVM只能优化常量值,对于引用,只有到真正运行到那一步的时候才能确定它的值,所以打印结果为false,true

然后再这样

 public static void main(String[] args) {        String s = "a";        String s1 = s + "b";    //        String s2 = "ab";//        System.out.println(s1 ==s2);        final String s3 = "c";        String s4 = s3 + "d";        String s5 = "cd";        System.out.println(s4 == s5);    }
查看.class文件




并不存在String ”ab“这两个值


今天累死再见



0 0