String 与 intern理解

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值