• 字符串常量池


    池这个词在java里并不罕见,比如运行时常量池,字符串常量池,线程池,数据库连接池等,所谓“池”就是为了资源复用,减少空间的占用,提高性能。

    1、什么是字符串常量池?

    JVM为了提高性能,减少内存开销,维护的一个存放字符串常量的内存区域,里面的字符串不允许重复,有长度限制,最大为65535字节(有兴趣的可以参考我的这篇博客:String的长度限制)。

    2、字符串常量池在哪?

    在JDK1.7以前,字符串常量池在方法区中,JDK1.7及以后的版本字符串常量池在堆中。
    如下图所示(简单示意,就不展开了):

    3、什么样的字符串会放入池中?

    我们平时使用String比较多的方式就是字面量赋值,String s = "abc",还有StringBuilder/StringBuffer,还有在类里定义的字符串变量,类里定义的字符串变量属于对象的一部分,不会存放在字符串常量池中。下面就分别讲一下这几种方式
    为了对比,把这种不常用的方式String s = new String("abc")也讲一下吧。

    3.1、字面量赋值String s = "xxx"方式

    String s1 = "长得帅弹玻璃球都帅";
    String s2 = "长得帅弹玻璃球都帅";
    System.out.println(s1 == s2);
    

    结果:

    s1和s2其实是指向了同一块内存地址,并且该内存地址在字符串常量池中,可见字面量赋值会直接放入字符串常量池中。
    内存分布:

    3.2、String s = new String("xxx")方式

    这种方式不常用,但为了和String s = "xxx"对比还是讲下

    String s1 = "长得帅弹玻璃球都帅";
    String s2 = "长得帅弹玻璃球都帅";
    String s3 = new String("长得帅弹玻璃球都帅");
    String s4 = new String("长得好看套麻布袋都好看");
    String s5 = new String("长得好看套麻布袋都好看");
    System.out.println(s1 == s2);
    System.out.println(s1 == s3);
    System.out.println(s4 == s5);
    

    结果:

    可见s3并没有在字符串常量池中,new出来的是对象,分配在堆上(注意并不是所有的对象都分配在堆上,这里我们不做讨论)
    s4与s5是堆上的两个不同对象,自然不等,但他们堆上的对象都指向常量池里的"长得好看套麻布袋都好看"
    对于new String("xxx")这种,如果常量池中没有xxx字符串,则会在常量池中建一个xxx字符串,比如这里的s3,s4
    如果常量池中有了xxx字符串,则其堆上的对象会指向常量池里的xxx字符串,比如这里的s5
    内存分布:

    我们用javap命令看下常量池:

    如果面试官问你,String s = new String("xxx")创建了几个对象,答曰:两个,字符串常量池里一个,堆上一个(如果结合xxx是否已经在常量池里存在分析,把内存分布图画出来,offer+1,哈哈)

    3.3、StringBuilder/StringBuffer方式

    StringBuilder/StringBuffer最后会调用toString()方法,而他们的toString()方法都是调的new String方法,所以和2.2一样
    StringBuffer的toString()方法:

    public synchronized String toString() {
            if (toStringCache == null) {
                toStringCache = Arrays.copyOfRange(value, 0, count);
            }
            return new String(toStringCache, true);
        }
    

    StringBuilder的toString()方法:

    public String toString() {
            // Create a copy, don't share the array
            return new String(value, 0, count);
        }
    

    4、intern方法

    当一个String对象调用intern()方法时,如果常量池中已经有同样的字符串了,则返回该对象的引用(在堆中就返回堆中的引用,在池中就返回池中的引用),如果没有,则将该对象添加到池中,并返回池中的引用。
    我在JDK1.8-java.lang.String类源码阅读有写过intern方法

    5、小实验

    String s1 = "hello"+"world";
    String s2 = new String("abc");
    String s3 = s2 +"def";
    

    内存分布:

    我们用javap命令看下常量池:

  • 相关阅读:
    深入研究Node.js的底层原理和高级使用
    Node.js实际案例分享
    Node.js的下载、安装、配置、Hello World、文档阅读
    Node.js初识
    sphinx初识
    Yii2中后台用前台的代码设置验证码显示不出来?
    彻底解决Yii2中网页刷新时验证码不刷新的问题
    yii2高级模板使用一个域名管理前后台
    Shot(三分)
    遮挡判断(模拟)
  • 原文地址:https://www.cnblogs.com/liuwhut/p/13188690.html
Copyright © 2020-2023  润新知