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

什么是字符串常量池_常量池中的字符串是对象吗关于字符串与字符串常量池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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 究竟什么是Java虚拟机(JVM)?

    究竟什么是Java虚拟机(JVM)?我们都知道,在Windows上,软件包后缀有exe,而苹果的MacOSX系统上没有安装exe。类似地,MacOSX系统上的软件安装包是dmg后缀,不能安装在Windows系统上。为什么不能安装不同系统上的软件,因为操作系统的底层实现是不同的。对于Windows系统,exe后缀的软件代码被编译成能被Windows系统识别的机器代码。对于MacOSX系统,最后将DMG后缀的软件代码编译为M…

    2022年7月8日
    17
  • SpringBoot与SpringCloud的版本对应详细版[通俗易懂]

    SpringBoot与SpringCloud的版本对应详细版[通俗易懂]缘起初学springcloud的朋友可能不知道,其实SpringBoot与SpringCloud需要版本对应,否则可能会造成很多意料之外的错误,比如eureka注册了结果找不到服务类啊,比如某些jar导入不进来啊,等等这些错误。下面列出来springBoot和springcloud的版本对应关系,需要配套使用,才不会出现各种奇怪的错误。关于maven仓库的版本列表spring-cloud…

    2022年4月29日
    242
  • pyqt5获取textedit内容_java点击按钮获取文本框内容

    pyqt5获取textedit内容_java点击按钮获取文本框内容我想从PyQt5.qtwidgestQinputDialog中的用户获取多个输入文本。。。在这段代码中,我可以只得到一个输入文本框,当我被单击按钮时,我想得到更多的输入文本框。更多信息请参见图片。。。在fromPyQt5.QtWidgetsimport(QApplication,QWidget,QPushButton,QLineEdit,QInputDialog,QHBoxLayout)im…

    2025年9月4日
    6
  • POJ 1011 Sticks

    POJ 1011 Sticks

    2021年12月7日
    40
  • HDFS分布式文件存储系统详解

    HDFS分布式文件存储系统详解HDFS简介一、HDFS:HadoopDistributedFileSystem          1. 一个分布式文件系统           2. 基于流数据模式访问和处理超大文件的需求而开发的          3. 适合应用在大规模数据集上     优点:                1.处理超大文件                   能用来存储管理PB级的数据 …

    2022年5月5日
    170
  • 请输入你的姓名C语言,VB程序题:要求:在屏幕上显示欢迎学习“VisualBasic”,并在“请输入你的姓名”标签后的文本框Text1中输入姓名;单击“你输入的姓名是”按钮,….. VB程序设计教…

    请输入你的姓名C语言,VB程序题:要求:在屏幕上显示欢迎学习“VisualBasic”,并在“请输入你的姓名”标签后的文本框Text1中输入姓名;单击“你输入的姓名是”按钮,….. VB程序设计教…VB程序题:要求:在屏幕上显示欢迎学习“VisualBasic”,并在“请输入你的姓名”标签后的文本框Text1中输入姓名;单击“你输入的姓名是”按钮,在Label3标签显示在文本框Text1输入的姓名。程序运行效果如下图所示。提示:1.所用的控件及属性设置见下表控件名属性Label1Caption=”欢迎学习VisualBasi”;Font属…

    2022年9月26日
    4

发表回复

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

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