关于String.intern的解析

因为在JDK1.6中是有永久代的(1.7)也有,不过为了响应JDK1.8的号召,所以在JDK1.7中把字符串常量池从永久代中放到了堆中

所以会导致一些问题

当我们调用intern方法时,会产生一些不一样的东西

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

    String s3 = new String("1") + new String("1");
    s3.intern();
    String s4 = "11";
    System.out.println(s3 == s4);

    //jdk6 下false false
    //jdk7 下false true

这个代码为例

在JDK1.6中,如果new了一个String对象,那么会在常量池中建立一个对应的对象,然后在堆中也会建立一个对象

相信很多 JAVA 程序员都做做类似 String s = new String("abc")这个语句创建了几个对象的题目。

这种题目主要就是为了考察程序员对字符串对象的常量池掌握与否。

上述的语句中是创建了2个对象,第一个对象是”abc”字符串存储在常量池中,第二个对象在JAVA Heap中的 String 对象。

点击查看详情

同理,JDK1.7也是,但是有些不一样的是intern方法

首先分析1.6,我们new了一个s,然后常量池和堆中就都有“1”这个对象,这个时候调用s.intern()其实就是说,常量池中如果每个这个对象就建立,有就直接返回这个对象的引用

String s2 = "1";这行代码直接从常量池中获取对象,所以肯定不会相等啊

String s3 = new String("1") + new String("1");也是一样

下面分析1.7

这个就有些不同了,因为常量池移到了堆中啊

new的时候同样会建立两个对象,s指向的是堆中的对象,但是s2指向的是常量池中的,所以还是false

但是s3和s4就不一样了,s3这句代码中现在生成了2个最终对象,是字符串常量池中的“1” 和 JAVA Heap 中的 s3引用指向的对象

此时s3引用对象内容是”11”,但此时常量池中是没有 “11”对象的。

然后这个时候我们调用intern方法,会在常量池中创建“11”这个对象,关键点是 jdk7 中常量池不在 Perm 区域了,这块做了调整。常量池中不需要再存储一份对象了,可以直接存储堆中的引用。这份引用指向 s3 引用的对象。 也就是说引用地址是相同的。

最后String s4 = "11"; 这句代码中”11”是显示声明的,因此会直接去常量池中创建,创建的时候发现已经有这个对象了,此时也就是指向 s3 引用对象的一个引用。所以 s4 引用就指向和 s3 一样了。因此最后的比较 s3 == s4 是 true。

        String a = new String("a");
        String b = new String("b");
        String d = a + b;
        d.intern();
        String c = "ab";
        System.out.println(c == d);

////////////////
true

为什么String是不可变的?

大概就四点原因吧,string类是final类型(无法继承,底层方法无法修改)+ private修饰,不提供set方法(无法直接在类外部直接访问修改)+ value数组也是final类型(保证数组引用指向不可变,在类内部有一点点作用,还有就是为了实现字符串常量池)+ string里面所有其他的方法的实现都没有动过value数组

全部评论

相关推荐

出自剑来:找工作就是运气大于实力的事 我们组的应届生也是上周在牛客招聘被百度的捞了,一周速通下of
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务