数据结构-----再谈String,字符串常量池,String对象的创建、intern方法的作用

文章目录

  • 1.字符串常量池
    • 1.1. 创建对象的思考
    • 2.2. 字符串常量池(StringTable)
    • 1.3. 再谈String对象创建
    • 1.4. intern方法

1.字符串常量池

1.1. 创建对象的思考

下面两种创建String对象的方式相同吗?

public static void main(String[] args) {
    String s1 = "hello";
    String s2 = "hello";
    String s3 = new String("hello");
    String s4 = new String("hello");
    System.out.println(s1 == s2);    // true
    System.out.println(s1 == s3);    // false
    System.out.println(s3 == s4);    // false
}

上述程序创建方式类似,为什么s1和s2引用的是同一个对象,而s3和s4不是呢?

  • 在Java中,字符串常量池是一种特殊的运行时常量池,用于存储String类的字符串字面常量。字符串常量池的主要目的是避免重复创建相同的字符串对象,从而节省内存和提高运行效率。

  • 当在Java程序中使用字符串字面常量(如"hello")时,如果字符串常量池中已经存在相同内容的字符串对象,则不会创建新的对象,而是直接引用已存在的对象。这样做可以减少内存消耗,特别是在字符串频繁创建和使用的情况下。

在Java程序中,类似于:1, 2, 3,3.14,“hello”等字面类型的常量经常频繁使用,为了使程序的运行速度更快、更节省内存,Java为8种基本数据类型和String类都提供了常量池。

“池” 是编程中的一种常见的, 重要的提升效率的方式, 我们会在未来的学习中遇到各种 “内存池”, “线程池”, “数据库连接池” …
比如:家里给大家打生活费的方式

  1. 家里经济拮据,每月定时打生活费,有时可能会晚,最差情况下可能需要向家里张口要,速度慢
  2. 家里有矿,一次性打一年的生活费放到银行卡中,自己随用随取,速度非常快

方式2,就是池化技术的一种示例,钱放在卡上,随用随取,效率非常高。常见的池化技术比如:数据库连接池、线程池等。

为了节省存储空间以及程序的运行效率,Java中引入了:

  1. Class文件常量池:每个.Java源文件编译后生成.Class文件中会保存当前类中的字面常量以及符号信息
  2. 运行时常量池:在.Class文件被加载时,.Class文件中的常量池被加载到内存中称为运行时常量池,运行时常量池每个类都有一份
  3. 字符串常量池:字符串常量池是运行时常量池中的一部分。在Java中,字符串是不可变的对象,为了节省内存并提高性能,字符串常量池被引入。当你创建一个字符串常量时(例如使用双引号括起来的字符串字面值),Java会首先检查字符串常量池中是否已经有相同值的字符串对象。如果有,则返回常量池中的对象引用,而不是创建一个新的字符串对象。这样可以避免创建重复的字符串对象,从而节省内存空间。

使用字符串常量池的优势在于:

  1. 节省内存:避免了创建大量相同内容的字符串对象,降低了内存占用。

  2. 提高效率:由于字符串常量池中的对象是可复用的,当需要创建相同内容的字符串时,可以直接引用常量池中的对象,避免了对象的重复创建和销毁过程,从而提高了程序的执行效率。

注意:虽然字符串常量池在一定程度上提高了程序的性能,但过度的使用字符串常量可能会导致一些问题。例如,如果在程序中大量使用字符串常量拼接,每次拼接都会生成一个新的String对象,这种情况下使用StringBuilder或StringBuffer等可变字符串类更合适,因为它们可以避免创建过多临时的String对象。

2.2. 字符串常量池(StringTable)

字符串常量池在JVM中是StringTable类,实际是一个固定大小的HashTable(一种高效用来进行查找的数据结构),不同JDK版本下字符串常量池的位置以及默认大小是不同的:

JDK版本字符串常量池位置大小设置
Java6(方法区)永久代固定大小:1009
Java7堆中可设置,没有大小限制,默认大小:60013
Java8堆中可设置,有范围限制,最小是1009

在这里插入图片描述

1.3. 再谈String对象创建

由于不同JDK版本对字符串常量池的处理方式不同,此处在Java8 HotSpot上分析

  1. 直接使用字符串常量进行赋值
public static void main(String[] args) {
    String s1 = "hello";
    String s2 = "hello";
    System.out.println(s1 == s2);    // true
}

在上述代码中有两个字符串字面常量 “hello”,那么它们都会被放入字符串常量池,并且只有一个实际的String对象用于表示这个内容。这样,当程序中其他部分使用了相同的字符串字面常量 “hello”,都会共享这个已存在的String对象。
在这里插入图片描述

在这里插入图片描述
存储字符串常量的时候,会先检查当前常量池是否存在你所要存储的常量。
在这里插入图片描述

  1. 通过new创建String类对象
public static void main(String[] args) {
    String s1 = "hello";
    String s2 = "hello";
    String s3 = new String("hello");
    String s4 = new String("hello");
    System.out.println(s1 == s2);    // true
    System.out.println(s1 == s3);    // false
    System.out.println(s3 == s4);    // false
}

常量池存在“hello”,此时不在常量中存储hello,此时只需要重新创建一个String对象那个,将它的value域存放hello数组的地址,指向那个hello数组
在这里插入图片描述

public static void main(String[] args) {
    String s1 = "hello";
    String s2 = "hello";
    String s3 = new String("world");
    String s4 = new String("world");
}

在这里插入图片描述
常量池不存在“world”,此时需要在常量中存储world。
在这里插入图片描述

结论:只要是new的对象,都是唯一的。

通过上面例子可以看出,使用常量串创建String类型对象的效率更高,而且更节省空间,用户也可以将创建的字符串对象通过intern方式添加进字符串常量池中。

1.4. intern方法

intern 是一个native方法(Native方法指:底层使用C++实现的,看不到其实现的源代码),该方法的作用是手动将创建的String对象添加到常量池中。

public static void main(String[] args) {
    char[] ch = new char[]{'a', 'b', 'c'};
    String s1 = new String(ch);     // s1对象并不在常量池中
    //s1.intern();                 // s1.intern();调用之后,会将s1对象的引用放入到常量池中
    String s2 = "abc";        // "abc" 在常量池中存在了,s2创建时直接用常量池中"abc"的引用
    System.out.println(s1 == s2);// 输出false
}
 

// 将上述方法打开之后,就会输出true

在这里插入图片描述

当代码运行到String s1 = new String(ch);时,我们发现在常量池中没有任何的数据,继续运行
在这里插入图片描述

public static void main(String[] args) {
    char[] ch = new char[]{'a', 'b', 'c'};
    String s1 = new String(ch);     // s1对象并不在常量池中
    s1.intern();                 // s1.intern();调用之后,会将s1对象的引用放入到常量池中
    String s2 = "abc";        // "abc" 在常量池中存在了,s2创建时直接用常量池中"abc"的引用
    System.out.println(s1 == s2);// 将方法打开之后,就会输出true
}

在这里插入图片描述
需要注意的是,虽然 intern() 方法可以减少重复字符串对象的内存占用,但滥用它也可能导致常量池过度膨胀,增加内存开销。在某些情况下,过度使用 intern() 方法可能会影响性能,因此在使用时需要谨慎考

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/417845.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Jmeter系列(5)线程数到底能设置多大

疑惑 一台设备的线程数到底可以设置多大? 线程数设置 经过一番搜索找到了这样的答案: Linux下,2g的 java内存,1m 的栈空间,最大启动线程数2000线程数建议不超过1000jmeter 能启动多少线程,由你的堆内存…

Decision Transformer

DT个人理解 emmm, 这里的Transformer 就和最近接触到的whisper一样,比起传统Transformer,自己还设计了针对特殊情况的tokens。比如whisper里对SOT,起始时间,语言种类等都指定了特殊tokens去做Decoder的输入和输出。 DT这里的作为输入的Tokens由RL里喜闻乐见的历史数据:…

docker save 命令 docker load 命令 快速复制容器

docker save 命令 docker load 命令 1、docker save 命令2、docker load 命令 1、docker save 命令 docker save 命令用于在系统上把正在使用的某个容器镜像 导出成容器镜像文件保存下载,以便在其他系统上导入这个容器镜像文件 以便快速在其他服务器上启动相同的容…

(正规api接口代发布权限)短视频账号矩阵系统实现开发--技术全自动化saas营销链路生态

短视频账号矩阵系统实现开发--技术全自动化saas营销链路生态源头开发(本篇禁止抄袭复刻) 一、短视频矩阵系统开发者架构 云罗短视频矩阵系统saas化系统,开发层将在CAP原则基础上使用分布式架构,对此网站的整体架构采用了基于B/S三层架构模式…

使用全局事件总线实现任意组件间的通讯

本文以vue2中爷孙组件通讯为例,需求是点击孙组件的按钮,实现关闭爷组件的弹窗。 全局事件总线是通过Vue实例的事件系统来实现组件之间的通讯,可以方便地在任何组件中进行事件的触发和监听。 以下是使用全局事件总线实现爷孙组件通讯的步骤&a…

33. 【Linux教程】Linux 用户组

前面小节介绍了 Linux 用户相关的增删改查,本小节介绍 Linux 用户组,Linux 系统中采取了一种安全机制(即用户组),用户组可以允许多个 Linux 用户共享同一种权限。 1. 用户组介绍 Linux 是多任务多用户的操作系统&…

Vite 构建的 Vue3 项目如何整合 Monaco Editor 代码编辑器

目录 🦁 一. 前言🦁 二. 探索过程2.1 安装2.2 配置 Monaco Editor2.3 编写 Monaco Editor 代码编辑器2.3.1 创建 Coding Editor 组件2.3.2 父组件使用 CodingEditor 组件 2.4 效果展示 三. 总结 🦁 一. 前言 各位好!我是&#x1…

什么是智能运维产品线和服务线

智能运维产品线和服务线涵盖了一系列自动化和智能化的技术和服务,旨在提升IT运维的效率和有效性。智能运维(AIOps)利用大数据、分析技术和机器学习能力来自动执行和简化运营工作流程,包括收集和汇总多源IT基础架构组件的数据、应用…

1、docker 基础命令

1、docker 运行镜像 docker run image tag 2、创建dockerfile&#xff08;构建容器的相关命令&#xff09; vim DockerFile 3、docker 构建容器镜像 docker build -t <image_name> . 4、docker 分层 5、查看镜像 docker images 6、docker 执行 docker run --name &…

【重要公告】BSV区块链协会全新推出“网络访问规则NAR”

​​发表时间&#xff1a;2024年2月15日 BSV区块链协会正式宣布已为BSV区块链推出一套全新的网络访问规则&#xff08;Network Access Rules&#xff0c;以下简称“NAR”&#xff09;。 NAR是一整套规则&#xff0c;用于规范BSV协会与BSV网络节点之间的关系。它基于比特币最初…

2024年怎么选类目?最容易起店的类目推荐,细分类目蕴含机会

大家好&#xff0c;我是电商花花。 做抖音小店选什么类目一直都是我们新手做店的一个大难题。 类目选对了&#xff0c;对于我们店铺就很容易出单&#xff0c;起店&#xff0c;如果选错了&#xff0c;店铺不出单或者没流量也是一个常见的事情。 而选品选类目本身就没有什么捷…

SikuliX使用介绍

1.SikuliX基本介绍 Sikuli 是 2009 年由 Tsung-Hsiang Chang 和 Tom Yeh在麻省理工学院用户界面设计小组的一个开源研究项目。1 年&#xff0c;两人都离开了 Sikuli-X-0.3rc2012 的项目&#xff0c;RaiMan决定接管开发和支持&#xff0c;并将其命名为 SikuliX。 S…

Pyhton的组合数据类型

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 生命对某些人来说是美丽的&#xff0c…

【MATLAB】MVMD_ MFE_SVM_LSTM 神经网络时序预测算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~也可转原文链接获取~ 1 基本定义 MVMD_MFE_SVM_LSTM神经网络时序预测算法结合了多变量多尺度分解&#xff08;MVMD&#xff09;、多尺度特征提取&#xff08;MFE&#xff09;、支持向量机&#xff08;SVM&#xff09;和长…

Redis 在 Linux 系统下安装部署的两种方式详细说明

小伙伴们好&#xff0c;欢迎关注&#xff0c;一起学习&#xff0c;无限进步 Redis安装和配置 1、首先在官网下载好redis-6.0.9.tar.gzhttp://redis.io/ 或者使用 wget 命令下载&#xff1a;wget http://download.redis.io/releases/redis-6.0.9.tar.gz 2、下载使用上传到阿里…

计算机组成原理1

文章目录 计算机组成原理图要学的内容 总的来说学习计算机组成原理是学什么?计算机的基本硬件组成CPU内存主板其他部件 冯诺依曼体系结构(Von Neumann architecture)不可编程存储计算机具体 大家好我是jiantaoyab,这是我作为学习的笔记,在这里分享给大家,还有一些书籍<深入…

docker安装es与kibana

docker安装es与kibana docker pull elasticsearch:7.11.2 docker network create esnet docker run --name es2 -p 9200:9200 -p 9300:9300 --network esnet -e "discovery.typesingle-node" -d elasticsearch:7.11.2 docker run -d -p 5601:5601 --network e…

力扣hot100题解(python版22-28题)

22、相交链表 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交**&#xff1a;** 题目数据 保证 整个链式结构中不存在环。 注意&#xff…

Python的报错类型

在编写python代码时&#xff0c;当不当使用时&#xff0c;python会给出错误提示&#xff0c;常见的错误类型有如下几种&#xff1a; 1.TpyeError类型错误 ① 传入的参数数量不对&#xff1a;如调abs()有且仅有1个参数&#xff0c;但给出了两个时&#xff0c;python会给出提示…

14:00进去,14:08就出来了,问的问题太变态。。。

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 刚从小厂出来&#xff0c;没想到在另一家公司我又寄了。 在这家…