zoukankan      html  css  js  c++  java
  • 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创建的对象。如果不存在,在运行常量池加入该对象或其引用。

  • 相关阅读:
    JavaMail入门第四篇 接收邮件
    JavaMail入门第三篇 发送邮件
    JavaMail入门第二篇 创建邮件
    JavaMail入门第一篇 邮件简介及API概述
    Java对象数组
    Mybatis Dao层注解及XML组合Dao的开发方式
    spring mvc常用注解总结
    组建自己的局域网(可以将PC机实现为服务器)
    局域网 FTP建立,搭建一个简易的局域网服务器
    公司局域网搭建
  • 原文地址:https://www.cnblogs.com/weixia-blog/p/9489994.html
Copyright © 2011-2022 走看看