Loading

String、常量池以及intern方法

.class文件常量池

常量池主要存放两类常量:字面量符号引用

字面量指文本字符串等。

符号引用指:

  • 类和接口的全限定名
  • 字段的名称和描述符
  • 方法的名称和描述符

编译期结束,当类加载器加载类时,.class文件常量被加入运行常量池,如果常量已存在则不再加载。

.class文件常量对象(如String)被创建是预定好的,除非已常量已存在则不再加载。

String intern方法

intern方法和JVM的运行常量池有关。

intern方法有两个作用:

  1. 将字符串字面量放入常量池(如果池没有的话)
  2. 返回这个常量的引用

第1个作用,在JDK1.6和JDK1.7中含义不同。

JDK1.6的运行常量池在堆外内存,调用intern方法,如果池没有的话将拷贝堆内实例对象到运行常量池,返回的引用自然地址在堆外。滥用该方法,则占用大量内存,抛出异常。

JDK1.7的运行常量池被移入堆内内存,调用intern方法,如果池没有的话将放入实例对象的引用,并返回实例对象的引用。

下面是段测试代码:

// 运行环境JDK1.8
public class Test {
    public static void main(String[] args) {
        // 情况1. 待测对象运行期才能确定
        String s1 = "hello";
        String s2 = ",world";
        String s3 = s1 + s2;
        System.out.println(s3.intern() == s3); // true
         
        // 情况2. 待测对象编译期已经确定
        String s4 = "你好" + ",世界";
        System.out.println(s4.intern() == s4); // true
         
        // 情况3. 待测对象运行期才能确定
        String s5 = "你好" + s2;
        System.out.println(s5.intern() == s5); // true
         
        // 情况4
        String s6 = new String("hello");
        String s7 = s6.intern();
        System.out.println(s6 == s7);       // false
    }
}

当我们使用javac命令编译完后,通过javap -v查看类文件。

Constant pool:
...
 #30 = Utf8               hello
#31 = Utf8               ,world
 ...
#40 = Utf8               你好,世界
#41 = Utf8               你好
 ...

常量池中已存在"hello",",world","你好,世界","你好"四个常量。

运行期时,上面四个常量进入运行常量池。

  • 情况1
    堆上创建一个对象(称为A),s3指向此对象。当A调用intern方法时,运行常量池不存在"hello,world"intern方法会在运行常量池中保存引用,并返回此引用,此引用指向对象A。故结果为true

  • 情况2
    两个字面量直接拼接,编译后只有拼接结果的常量,运行期进入运行常量池,s4指向常量池,因为常量池存在此常量,故s4.intern()s3指向相同。

  • 情况3
    堆上创建一个对象(称为B),s5指向此对象。当B调用intern方法时,运行常量池不存在"你好,world"intern方法会在运行常量池中保存引用,并返回此引用,此引用指向对象B。故结果为true

  • 情况4
    堆上创建一个对象(称为C),s6指向此对象。当C调用intern方法时,运行常量池存在"hello"intern方法会返回一个指向常量池的引用。此引用和s6不同,故结果为true

总结

intern方法可以在运行期往运行常量池中添加常量。

intern方法可以避免重复创建相同的String实例,优化内存。

JDK1.7,此方法通过常量池判断是否存在相同的String实例,如果存在,将引用指向同个对象,将其他相同但冗余的对象取消引用,利用内存回收机制回收new创建的对象。如果不存在,在运行常量池加入该对象或其引用。

posted @ 2018-08-16 21:07  未夏  阅读(271)  评论(0编辑  收藏  举报