什么是字符串常量池_常量池中的字符串是对象吗

什么是字符串常量池_常量池中的字符串是对象吗关于字符串与字符串常量池JDK1.8-1.9,String底层从char数组变成了byte数组,原因是部分字符仅占一个byte,而堆中含有大量的String字符串,该优化能节省较多空间。StringTable为什么要调整(移入堆内)(JDK1.6-1.7)permSize默认比较小永久代垃圾回收频率低字符串拼接操作常量与常量的拼接结果在常量池,原理是编译器优化常量池中不会存在相同内容的常量只要其中一个是变量,结果就在堆中。变量拼接的原理是StringBuilder(final不算变量)

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

JDK1.8-1.9,String底层从char数组变成了byte数组,原因是部分字符仅占一个byte,而堆中含有大量的String字符串,该优化能节省较多空间。

关于常量池

常量池/Class常量池(Constant pool)

常量池,也叫 Class 常量池(常量池==Class常量池)。Java文件被编译成 Class文件,Class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项就是常量池,常量池是当Class文件被Java虚拟机加载进来后存放在方法区 各种字面量 (Literal)和 符号引用 。
在这里插入图片描述

运行时常量池(Runtime constant pool)

运行时常量池是方法区的一部分。运行时常量池是当Class文件被加载到内存后,Java虚拟机会 将Class文件常量池里的内容转移到运行时常量池里(运行时常量池也是每个类都有一个)。运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中

只存放字符串引用

在这里插入图片描述

字符串常量池(String pool/String table)

字符串常量池又称为:字符串池,全局字符串池,英文也叫String Pool。 在工作中,String类是我们使用频率非常高的一种对象类型。JVM为了提升性能和减少内存开销,避免字符串的重复创建,其维护了一块特殊的内存空间:字符串常量池。字符串常量池由String类私有的维护

堆里边的字符串常量池存放的是字符串的引用或者字符串(两者都有)

比如new String(“test”)就会先在常量池中检查是否存在,不存在则在常量池中创建,然后堆中创建其引用。

常量池和字符串常量池的版本变化

  • 在JDK1.7之前运行时常量池逻辑包含字符串常量池存放在方法区, 此时hotspot虚拟机对方法区的实现为永久代
  • 在JDK1.7 字符串常量池、静态变量等被从方法区拿到了堆中, 这里没有提到运行时常量池,也就是说 字符串常量池被单独拿到堆,运行时常量池剩下的东西还在方法区, 也就是hotspot中的永久代
  • 在JDK1.8 hotspot移除了永久代用元空间(Metaspace)取而代之, 这时候字符串常量池还在堆, 运行时常量池还在方法区, 只不过方法区的实现从永久代变成了元空间(Metaspace)
  • 补充:
    • 对象只能存在于堆中(虚拟机规范的定义),所以String实体只能存在于堆中,
    • 运行时常量池存放的是字面量引用
    • 使用双引号方式显式声明的字符串,则直接放入字符串常量池中(final修饰的“变量”可以直接看作双引号字面量)

StringTable为什么要调整(1.6-1.7)

  • permSize默认比较小
  • 永久代垃圾回收频率低

字符串拼接操作

  • 常量与常量的拼接结果在常量池,原理是编译器优化
  • 常量池中不会存在相同内容的常量
  • 只要其中一个是变量,结果就在堆中。变量拼接的原理是StringBuilder(final不算变量),返回String对象
  • 如果拼接的结果调用intern()方法,则注定将常量池中还没有的字符串对象放入池中,并返回此对象地址

所以建议多使用final定义字符串,并且不使用new,对于new String()声明final不会优化

示例

    public static boolean IsInPool(String str){ 
   
        return str == str.intern();
    }
    public static void main(String[] args) { 
   
        final String a1 = "a";
        final String a2 = "b";
        String a3 = a1 + a2;
        String limit1 = "ab";

        String a4 = "c";
        String a5 = "d";
        String a6 = a4 + a5;
        String limit2 = "cd";

        String b1 = new String("e");
        String b2 = new String("f");
        String b3 = b1 + b2;
        String limit3 = "ef";

        final String b4 = new String("g");
        final String b5 = new String("h");
        String b6 = b4 + b5;
        final String limit4 = "gh";

        System.out.println(IsInPool(a3));//true
        System.out.println(IsInPool(a6));//false
        System.out.println(IsInPool(b3));//false
        System.out.println(IsInPool(b6));//false

image-20211008214506729

字符串的创建与常量池

String两种创建方式

  • 方式一(str值和字符串常量池中字面量地址相等)
String str = "abc"
  1. 检查字符串常量池是否存在该字符串,存在则不创建并且返回该字符串的引用
  2. 不存在则在字符串常量池中创建该字符串常量并返回其常量池中地址
  • 方式二(str值和字符串常量池中字面量地址不相等)
String str = new String("abc")
  1. 检查字符串常量池是否存在该字符串,存在则不创建,不存在则创建该字符串常量
  2. 在堆中创建该对象
  3. 返回堆中该对象的引用

普遍地

使用双引号方式显式存在的字符串,则直接放入字符串常量池中(final修饰的“变量”可以直接看作双引号字面量)

一些测试(JDK1.8)

情况一:

    public static void main(String[] args) { 
   
        String a1 = "a";
        String a2 = new String("b");
        String a3 = "c";
        String a4 = a1 + a2;
        String a5 = a1 + a3;
// String at = "a"+"c";
// String at1 = "a"+"b";

        System.out.println(IsInPool(a1));//true
        System.out.println(IsInPool("b"));//true
        System.out.println(IsInPool(a2));//false
        System.out.println(IsInPool(a3));//true

        System.out.println(IsInPool(a4));//true
        System.out.println(IsInPool("ab"));//true
        System.out.println(IsInPool(a5));//true
        System.out.println(IsInPool("ac"));//true
    }

情况二:

    public static void main(String[] args) { 
   
        String a1 = "a";
        String a2 = new String("b");
        String a3 = "c";
        String a4 = a1 + a2;
        String a5 = a1 + a3;
        String at = "a"+"c";
        String at1 = "a"+"b";

        System.out.println(IsInPool(a1));//true
        System.out.println(IsInPool("b"));//true
        System.out.println(IsInPool(a2));//false
        System.out.println(IsInPool(a3));//true

        System.out.println(IsInPool(a4));//false
        System.out.println(IsInPool("ab"));//true
        System.out.println(IsInPool(a5));//false
        System.out.println(IsInPool("ac"));//t
    }

IsInpool函数

    //使用这个函数需要在这个函数前使用双引号字面量使得字符串直接被加入常量池中
	//使用顺序应为待测字符串->字面量->IsInPool

	public static boolean IsInPool(String str){ 
   
        return str == str.intern();
    }

对于intern函数的理解

调用这个方法之后就是去看当前字符串是否在字符串常量池中已经存在引用

(1)存 在:那就直接返回该字符串在字符串常量池中所对应的地址给栈中要引用这个字符串的变量。

(2)不存在
① jdk 1.6:先在字符串常量池中创建该字符串,地址与堆中字符串地址不相同。然后再返回刚创建的字符串在字符串常量池中所对应的地址给栈中要引用这个字符串的变量。

② jdk 1.7及以后:直接将堆中(不是字符串常量池中)该字符串的地址复制到字符串常量池中,这样字符串常量池就有了该字符串的地址引用,也可以说此时字符串常量池中的字符串只是一个对 堆中字符串对象的引用,它们两个的地址相同,然后再把这个地址返回给栈中要引用这个字符串的变量。

对测试的解释

  • 第一次两个拼接测试为true,因为intern函数将堆中字符串对象引用复制到字符串常量池中,所以二者自然相等
  • 第二次两个拼接测试为false,因为intern检查到已经存在该字符常量,且堆常量池中保存的是字符串的值,二者自然不相等
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/164773.html原文链接:https://javaforall.net

(0)
上一篇 2022年7月28日 上午6:00
下一篇 2022年7月28日 上午6:16


相关推荐

  • 到底创建了几个Session

    到底创建了几个Session

    2022年3月7日
    40
  • 密钥库文件不存在: debug.keystore

    密钥库文件不存在: debug.keystore

    2021年9月30日
    60
  • IDEA配置Maven——(傻瓜式教程)

    IDEA配置Maven——(傻瓜式教程)3 配置 MAVEN HOMEmaven 的使用是在 jdk 的基础上 所以电脑必须有 jdk 第一步 新增环境变量 MAVEN HOME 第二步 在 path 环境变量中添加 MAVEN HOME bin 找到环境变量配置界面第三步 测试 按住 win R 输入 cmd 进入黑窗口控制台 输入命令 mvn v 如果出现以下 maven 的版本信息 则说明 maven 的安装与环境变量的配置均正确 版权声明 本文为 CSDN 博主 伏加特遇上西柚 的原创文章 遵循 CC4 0

    2026年3月17日
    10
  • java程序设计图书管理系统源码(java图书管理系统设计报告)

    图书管理系统需实现的功能如下:(1)用户管理:包括用户的注册于登录。(2)图书管理:包括录入、查询、修改和删除图书信息。(3)借书:包括借阅图书和查看借书记录。(4)还书:包括还书和查看还书记录。(5)为了保证系统安全,进入系统时,对用户登录的密码进行加密与解密。源码、课程设计报告、数据库表图的百度网盘链接:https://pan.baidu.com/s…

    2022年4月12日
    85
  • 软引用和弱引用的区别_强引用软引用弱引用虚引用的区别

    软引用和弱引用的区别_强引用软引用弱引用虚引用的区别示例代码:importjava.lang.ref.SoftReference;/***@authorchenjc*@since2020-01-13*/publicclassSoftReferenceTest{/***使用JVM参数-Xmx10m运行程序**@paramargs*@throwsI…

    2025年10月6日
    7
  • 面向接口编程思想(面向对象思想)

    面向接口编程思想(面向对象思想)看到一篇讲解生动有趣的博客 nbsp 拿来分享一下原文链接如下 面向接口编程 nbsp nbsp 开启故事之旅 面向接口编程思想 有一天 我想盖个房子 当然我自己是肯定盖不起来的 我要找村东头的强壮搬砖大哥 村南头的技术娴熟的砌墙师傅 村北头的水泥大哥和邻村的贴瓷砖师傅等 我的计划是这样的 先找人 找到村东头的搬砖大哥 找到村南头的砌墙师傅 找到村西头的水泥大哥 找到邻村里

    2026年3月17日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号