让人望而却步的String及intern()方法

摘要

java.lang.String中的public native String intern();返回值:如果常量池中有此字符,那么就返回字符串常量池中的字符的地址,由于字符串常量池也在堆上,所以返回的也是堆上的地址;如果字符串常量池没有此字符,就将这个对象的地址放入字符串常量池中,并返回放入的对象地址;

public class StringConstruct {
    public static void main(String[] args) {
        String s1=new String("A")+new String("B");
        System.out.println(s1==s1.intern());
        System.out.println(s1=="AB");
    }
}

结果都是true;

逐句分析
String s1=new String("A")+new String("B");

这一句会在常量池中创建A、B并在堆上存储A和B在常量池的引用, 在栈上创建引用变量s1,而s1引用的对象实体是"AB",因此会在堆上创建"AB",同时把"AB"的地址复制给s1;
注意此时并没有把"AB"放在字符串常量池中;

  • 关于str的构造一些补充:
    使用构造函数和直接赋予字面值创建String对象是不一样的;使用构造函数会在堆上创建一个对象对象有属性value、coder、hash……;其他的我们先不看,单说这个value;它的源码是这样的:private final byte[] value;他是用来引用一个常量,这个字符数组并没有开辟空间;也就是String对象注定存储的是字符的地址;
    而直接赋值一个字面值字符串,是不会在堆上创建对象的,也就没有alue、coder、hash……这些字段;
    而String s1=new String(“A”)+new String(“B”);归根结底是直接赋值一个字面值字符串;那么“AB”放在哪呢?答案是堆上,并且不是常量池中;就是随便找了个空间放进去,并在栈上引用;
 System.out.println(s1==s1.intern());

执行s1.intern()方法时JDK1.6和1.7是不同的:
对于JDK1.6:它会检查常量池中有没有s1引用的字符串,如果没有就会将这个字符串添加进去;然后返回这个常量在常量池上的地址(引用);
对于JDK1.7 同样它会先检查常量池中有没有s1引用的字符串,如果没有就会将这个字符串的引用(就是s1存储的内容,也就是’'AB"在堆上的地址)添加进去,然后返回这个常量的在堆上的引用(地址);
分析语句 s1 == s1.intern() : s1中存储的是堆上"AB"的地址;而s1.intern()返回这个常量的在堆上的引用;这也就是为什么s1 == s1.intern()结果是true了

System.out.println(s1=="AB");

这一句"AB"代表一个匿名对象,可以看作s2 = “AB”,然后比较(s1 == s2)在创建s2对象时由于可以找到,通过常量池上存储的引用或字面值常量找到。所以s2存储的从常量池中取得”AB“的堆上地址(s1的值),结果也是true;
简单画图看一下:在这里插入图片描述

在看一个例子:
这是一个新的程序,不受的上面例子的影响;

	String s = new String("A");
        s.intern();
        String s2 = "A";
        System.out.println(s == s2);

先说一下运行结果吧:false
逐行分析:

String s = new String("A");

这一行会在常量池中先查找能不能找到A或A 的引用,很显然没有,那么就会在常量池创建字符A,然后在堆上创建对象,对象中存储常量池字符的地址,同时在栈上创建s,s存储堆上对象的地址;
那么在执行第二句

s.intern();

这时常量池已经有了”A“,此方法就会返回常量池上”A”的地址;
第三句

String s2 = "A";

此时将不会在堆上重新创建对象了,s2直接存储常量池的“A“的地址;
那么结果就显而易见了;
在看例子

String s3 = new String("A") + new String("B");
s3.intern();
String s4 = "AB";
System.out.println(s3 == s4);

s3.intern();执行这个代码是常量池就存储了”AB“堆上对象的地址;
String s4 = “AB”;此时s4s2直接存储常量池中存储的“AB“的对象地址;
那么结果就显而易见了为true;
需要补充一点前面说的常量池中存储的是:堆上对象内存的地址或常量直接值;其实Java1.7之后常量池也是在堆上,所以创建一个常量池中有的对象时,栈上的引用指向常量池数据,就是堆上的;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值