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

什么是字符串常量池_常量池中的字符串是对象吗关于字符串与字符串常量池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


相关推荐

  • git fetch 更新远程代码到本地仓库

    git fetch 更新远程代码到本地仓库

    2021年11月8日
    55
  • 看国内大厂如何在软件研发中玩转智能体(agents)?

    看国内大厂如何在软件研发中玩转智能体(agents)?

    2026年3月15日
    2
  • Framework7 Vue 教程 入门 学习

    Framework7 Vue 教程 入门 学习网上关于Framework7的博客、学习资料少之又少,所以我想把我学习Framework7Vue的入门记录一下。Framework7Framework7是一个开源免费的框架可以用来开发混合移动应用(原生和HTML混合)或者开发iOS&Android风格的WEBAPP。也可以用来作为原型开发工具,可以迅速创建一个应用的原型。Framework7最主要的功能是可以…

    2022年6月3日
    194
  • android galley实现画廊效果

    android galley实现画廊效果青春流水指间、每段路,都有即将要来的旅程每颗心,都有值得期待的成分Android之ImageSwitcher,Gallery用法今天在做一个软件界面时用到了ImageSwitcher和Gallery控件,在看API时,感觉上面的例子讲的不是很具体,效率并不高。在这里我就以一个图片浏览功能来具体说明这两个控件的用法。首先看运行效果:在这里图片我用的是API中的图

    2022年5月16日
    42
  • pandas用平均值填充缺失值_pandas筛选列不为空值

    pandas用平均值填充缺失值_pandas筛选列不为空值官方fillna方法文档pandas中fillna()方法,能够使用指定的方法填充NA/NaN值。1.函数详解函数形式:fillna(value=None,method=None,axis=None,inplace=False,limit=None,downcast=None,**kwargs)参数:value:用于填充的空值的值。method:{‘backfill…

    2022年8月12日
    11
  • 使用ABP打造SAAS系统(2)——前端框架选择[通俗易懂]

    使用ABP打造SAAS系统(2)——前端框架选择[通俗易懂]一、流行框架比较  作者用过的前端框架不少,曾经还在一个项目中同时使用两套框架控件(年少无知、效率特慢),所以可供选择的前端框架有不少:easyui: 优点:非常成熟的框架,基于iframe可以进行多线程操作 缺点:由于采用iframe,不优化情况下效率是个问题,同时iframe导致对SEO的支持不是很好,自带风格不是很符合现在人的口味,自己定义风格有点浪费时间,顺便提供下本人自…

    2026年1月26日
    5

发表回复

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

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