String的intern()方法浅析

2023-10-29

简介

String.intern()方法是一种手动将字符串加入常量池中的native方法,原理如下:如果在当前类的常量池中存在与调用intern()方法的字符串等值的字符串,就直接返回常量池中相应字符串的引用,否则在常量池中复制一份该字符串(Jdk7中会直接在常量池中保存当前字符串的引用),并将其引用返回;因此,只要是堆中等值的String对象,使用intern()方法返回的都是常量池中同一个String引用,所以,这些等值的String对象通过intern()后使用==是可以匹配的。

预备知识

一、创建String对象的两种方式 

创建String对象分为在堆中创建和在字符串常量池中创建。 

1、在字符串常量池中创建String对象

String str1 = "计算机";
String str2 = "计算机";
System.out.println(str1 == str2);

第一行代码

  • 执行到括号中“计算机”的时候,会在字符串常量池中添加“计算机”对象。
  • 然后将栈中的str1变量指向该对象。 

第二行代码

  • 执行到括号中“计算机”的时候,发现字符串常量池已存在“计算机”对象。
  • 为避免重复创建对象,将栈中的str2变量指向字符串常量池已存在的对象,字符串常量池存在的原因正是如此。 

 补充:

//常量字符串的"+"操作,编译阶段直接会合成为一个字符串。
String str = "计算" + "机"; //编译时合并成String str = "计算机";

//对于final字段,编译期直接进行了常量替换。
final String str1 = "计算";
final String str2 = "机";
String str3 = str1 + str2; //编译时直接替换成了String str3 = "计算" + "机";

2、在堆中创建String对象

String str1 = new String("计算机");
String str2 = new String("计算机");
System.out.println(str1 == str2);

第一行代码

  • 执行到括号中“计算机”的时候,会在字符串常量池中添加“计算机”对象。
  • 执行完毕后会在堆中创建“计算机”对象,并将栈中的str1变量指向该对象。 

第二行代码

  • 执行到括号中“计算机”的时候,发现字符串常量池已存在“计算机”对象。
  • 执行完毕后会因为new关键字在堆中创建出一个新的对象,并将栈中的变量str2指向该对象。  

 二、不同jdk版本中的intern()实现

jvm对字符串常量池在不同的jdk版本有不同的划分,内存的变化也会影响intern方法的执行。

JDK6 JDK7及之后
intern()方法 会把首次遇到的字符串实例复制到常量池中,并返回此引用 会把首次遇到的字符串实例的引用添加到常量池中,并返回此引用
  • Jdk6中常量池位于PermGen(永久代)中,PermGen是一块主要用于存放已加载的类信息和字符串池的大小固定的区域。Jdk6中使用intern()方法的主要问题就在于常量池被保存在PermGen中:首先,PermGen是一块大小固定的区域,一般不同的平台PermGen的默认大小也不相同,大致在32M到96M之间。所以不能对不受控制的运行时字符串(如用户输入信息等)使用intern()方法,否则很有可能会引发PermGen内存溢出;其次String对象保存在Java堆区,Java堆区与PermGen是物理隔离的,因此如果对多个不等值的字符串对象执行intern操作,则会导致内存中存在许多重复的字符串,会造成性能损失。
  • Jdk7将常量池从PermGen区移到了Java堆区,执行intern操作时,如果常量池已经存在该字符串,则直接返回字符串引用,否则复制该字符串对象的引用到常量池中并返回。堆区的大小一般不受限,所以将常量池从PremGen区移到堆区使得常量池的使用不再受限于固定大小。除此之外,位于堆区的常量池中的对象可以被垃圾回收。当常量池中的字符串不再存在指向它的引用时,JVM就会回收该字符串。

实例解析

代码一

String s1 = new String("1"); //常量池中创建"1",堆中创建"1"
s1.intern();          //常量池中已有"1",所以jdk6和jkd7都是返回指向常量池"1"的引用,
                      //但因为该语句没有赋值操作,所以s1仍指向堆中"1"
String s2 = "1";      //s2指向常量池中已存在的"1"
System.out.println(s1==s2);  //s1指向堆中"1",s2指向常量池中"1",false

 jdk6、7、8都返回false

代码二

String s3 = new String("1") + new String("1"); //常量池生成一个"1",堆生成一个"11"
                                               //s3指向堆中"11"
                                       //中间还有2个匿名的new String("1")暂不讨论
s3.intern();             //因为常量池中不存在"11",
                         //jdk6会将堆中"11"复制到常量池中,
                         //jdk7则将堆中"11"的引用添加到常量池中,
                         //此时s3仍指向堆中"11"
String s4 = "11";        //因为常量池中已存在"11"或其引用,s4指向常量池中"11"
System.out.println(s3==s4);  //jdk6中,s4指向常量池中"11",s3指向堆中"11",false
                             //jdk7中,s4指向常量池中指向堆中"11"的引用,true

 在jdk6中返回false,jdk7及以上返回true

适用场景

Jdk6 中常量池位于PremGen区,大小受限,不建议使用String.intern()方法,不过Jdk7 将常量池移到了Java堆区,大小可控,可以重新考虑使用String.intern()方法。

intern()方法优点:执行速度非常快,直接使用==进行比较要比使用equals()方法快很多;内存占用少。虽然intern()方法的优点看上去很诱人,但由于intern()操作每次都需要与常量池中的数据进行比较以查看常量池中是否存在等值数据,同时JVM需要确保常量池中的数据的唯一性,这就涉及到加锁机制,这些操作都是有需要占用CPU时间的,所以如果进行intern操作的是大量不会被重复利用的String的话,则有点得不偿失。由此可见,String.intern()主要 适用于只有有限值,并且这些有限值会被重复利用的场景,如数据库表中的列名、人的姓氏、编码类型等。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

String的intern()方法浅析 的相关文章

  • Java new Date() 打印

    刚刚学习 Java 我知道这可能听起来很愚蠢 但我不得不问 System out print new Date 我知道参数中的任何内容都会转换为字符串 最终值是 new Date 返回对 Date 对象的引用 那么它是如何打印这个的呢 Mo
  • Spring Batch 多线程 - 如何使每个线程读取唯一的记录?

    这个问题在很多论坛上都被问过很多次了 但我没有看到适合我的答案 我正在尝试在我的 Spring Batch 实现中实现多线程步骤 有一个包含 100k 条记录的临时表 想要在 10 个线程中处理它 每个线程的提交间隔为 300 因此在任何时
  • Java - 将节点添加到列表的末尾?

    这是我所拥有的 public class Node Object data Node next Node Object data Node next this data data this next next public Object g
  • Java JDBC:更改表

    我希望对此表进行以下修改 添加 状态列 varchar 20 日期列 时间戳 我不确定该怎么做 String createTable Create table aircraft aircraftNumber int airLineCompa
  • 使用 Android 发送 HTTP Post 请求

    我一直在尝试从 SO 和其他网站上的大量示例中学习 但我无法弄清楚为什么我编写的示例不起作用 我正在构建一个小型概念验证应用程序 它可以识别语音并将其 文本 作为 POST 请求发送到 node js 服务器 我已确认语音识别有效 并且服务
  • Final字段的线程安全

    假设我有一个 JavaBeanUser这是从另一个线程更新的 如下所示 public class A private final User user public A User user this user user public void
  • 列出jshell中所有活动的方法

    是否有任何命令可以打印当前 jshell 会话中所有新创建的方法 类似的东西 list但仅适用于方法 您正在寻找命令 methods all 它会打印所有方法 包括启动 JShell 时添加的方法 以及失败 被覆盖或删除的方法 对于您声明的
  • JavaMail 只获取新邮件

    我想知道是否有一种方法可以在javamail中只获取新消息 例如 在初始加载时 获取收件箱中的所有消息并存储它们 然后 每当应用程序再次加载时 仅获取新消息 而不是再次重新加载它们 javamail 可以做到这一点吗 它是如何工作的 一些背
  • 磁模拟

    假设我在 n m 像素的 2D 表面上有 p 个节点 我希望这些节点相互吸引 使得它们相距越远吸引力就越强 但是 如果两个节点之间的距离 比如 d A B 小于某个阈值 比如 k 那么它们就会开始排斥 谁能让我开始编写一些关于如何随时间更新
  • Spring @RequestMapping 带有可选参数

    我的控制器在请求映射中存在可选参数的问题 请查看下面的控制器 GetMapping produces MediaType APPLICATION JSON VALUE public ResponseEntity
  • 无法解析插件 Java Spring

    我正在使用 IntelliJ IDEA 并且我尝试通过 maven 安装依赖项 但它给了我这些错误 Cannot resolve plugin org apache maven plugins maven clean plugin 3 0
  • 在两个活动之间传输数据[重复]

    这个问题在这里已经有答案了 我正在尝试在两个不同的活动之间发送和接收数据 我在这个网站上看到了一些其他问题 但没有任何问题涉及保留头等舱的状态 例如 如果我想从 A 类发送一个整数 X 到 B 类 然后对整数 X 进行一些操作 然后将其发送
  • Java列表的线程安全

    我有一个列表 它将在线程安全上下文或非线程安全上下文中使用 究竟会是哪一个 无法提前确定 在这种特殊情况下 每当列表进入非线程安全上下文时 我都会使用它来包装它 Collections synchronizedList 但如果不进入非线程安
  • 如何在桌面浏览器上使用 webdriver 移动网络

    我正在使用 selenium webdriver 进行 AUT 被测应用程序 的功能测试自动化 AUT 是响应式网络 我几乎完成了桌面浏览器的不同测试用例 现在 相同的测试用例也适用于移动浏览器 因为可以从移动浏览器访问 AUT 由于它是响
  • 编译器抱怨“缺少返回语句”,即使不可能达到缺少返回语句的条件

    在下面的方法中 编译器抱怨缺少退货声明即使该方法只有一条路径 并且它包含一个return陈述 抑制错误需要另一个return陈述 public int foo if true return 5 鉴于Java编译器可以识别无限循环 https
  • 在 Maven 依赖项中指定 jar 和 test-jar 类型

    我有一个名为 commons 的项目 其中包含运行时和测试的常见内容 在主项目中 我添加了公共资源的依赖项
  • 有没有办法为Java的字符集名称添加别名

    我收到一个异常 埋藏在第 3 方库中 消息如下 java io UnsupportedEncodingException BIG 5 我认为发生这种情况是因为 Java 没有定义这个名称java nio charset Charset Ch
  • java.lang.IllegalStateException:驱动程序可执行文件的路径必须由 webdriver.chrome.driver 系统属性设置 - Similiar 不回答

    尝试学习 Selenium 我打开了类似的问题 但似乎没有任何帮助 我的代码 package seleniumPractice import org openqa selenium WebDriver import org openqa s
  • 将 List 转换为 JSON

    Hi guys 有人可以帮助我 如何将我的 HQL 查询结果转换为带有对象列表的 JSON 并通过休息服务获取它 这是我的服务方法 它返回查询结果列表 Override public List
  • 使用 xpath 和 vtd-xml 以字符串形式获取元素的子节点和文本

    这是我的 XML 的一部分

随机推荐

  • 【JavaWeb_Part05】JDBC?弱爆了,看看轻量级的 Mybatis FreeStyle

    开篇 上篇文章我们已经讲了 Mybatis 的入门以及简单的对单表进行增删改查 那么今天我们就来讲一下使用 mybatis 开发dao的两种方式以及 mysql 比较厉害的动态 sql 利用 mybatis 开发 DAO 1 原始的方式开发
  • 多线程之间共享数据的方式探讨

    多线程之间共享数据的方式探讨 方式一 代码一致 如果每个线程执行的代码相同 可以用一个 Runnable 对象 这个 Runnable 对象中存放那个共享数据 卖票系统可以这样做 public class MultiThreadShareD
  • java系统运维:使用java自带的工具监控系统(java)虚机的运行

    公司采用的B S架构开发的系统林林总总 有时候系统不稳定 分析起来很头疼 除了看日志 还很希望能知道系统虚拟机的运行情况 java 虚拟机从1 5开始 有类似的工具 jconsole 1 6开始不但有jconsole 还有升级版 jvisu
  • 图神经网络(一)DGL框架搭建GCN图卷积神经网络模型

    一 DGL DGL是基于pytorch开发的一个专门用于图神经网络模型搭建的框架 到现在为止 DGL已经高度封装了如GCN GraphSage GAT等常见的图神经网络模型 可以直接调用 比较方便 当然针对非常想挑战自己的编程能力又或者非常
  • 电梯系统OO设计

    理论上应该先黑盒用例 分析需要求 系统边界的输入输出 再白盒类图 但是对于现实世界模拟的OO 个人感觉先emulate现实世界 初步识别类和类之间的关系 再用用例和顺序图丰富 修正类图 识别类 最主要的原则是封装 数据和数据的操作封装成一个
  • 【Linux】ibus输入法安装教程

    My name is Linus and I am your God Linus Torvalds 安装其他输入法总是会遇到各种问题 而当新的发行版出来时 原来的输入法总是就失效了或是其他问题不能使用 经过我的多次实测 发现ibus输入法非
  • uniapp小程序实现上传图片功能,并显示上传进度

    效果图 实现方法 一 通过uni chooseMedia OBJECT 方法 拍摄或从手机相册中选择图片或视频 官方文档链接 https uniapp dcloud net cn api media video html choosemed
  • 正则表达式获取两个字符之间的字符串信息

    今天工作有一个需求就是捕获两个字符之间的字符串信息 类似就是AcakeB这个字符串中提取cake 当时只想到如下的表达式 A B 复制代码 上述是将以A开头和以B结尾的字符串提取出来 但是本意是不想要有A和B了 通过查资料发现了如下写法 l
  • JSP四大作用域

    一 ServletContext 1 生命周期 当Web应用被加载进容器时创建代表整个web应用的ServletContext对象 当服务器关闭或Web应用被移除时 ServletContext对象跟着销毁 2 作用范围 整个Web应用 3
  • sql两张表统计求比分比。

    数据 表一 compay 表二person 第一步 第一张表统计结果 select sum money from person 第二张表统计结果 select sum money from compay 相除结果 select select
  • 读取word中表格的数据

    在pro文件中加入 QT axcontainer 按步骤 1 创建Word应用程序对象 2 获取文档集 3 打开文档 4 获取活动表格 5 读取表格中的信息 QAxObject myword new QAxObject Word Appli
  • 区块链-技术简介(*)

    1 什么是区块链 区块链技术是利用块链式数据结构来验证与存储数据 利用分布式节点共识算法来生成和更新数据 利用密码学的方式保证数据传输和访问的安全 利用由自动化脚本代码组成的智能合约来编程和操作数据的一种全新的分布式基础架构与计算范式 简单
  • PTA(Basic Level) 1029_旧键盘 Python实现

    1029 旧键盘 Python实现 下面是题目信息 旧键盘上坏了几个键 于是在敲一段文字的时候 对应的字符就不会出现 现在给出应该输入的一段文字 以及实际被输入的文字 请你列出肯定坏掉的那些键 输入格式 输入在 2 行中分别给出应该输入的文
  • 【AI PC端算法优化】二,一步步优化自然饱和度算法

    上一节的RGB转灰度图算法我又做了两个相关优化 加入了多线程以及去掉了上次SSE计算中的一些重复计算 现在相对于传统实现已经可以获得4倍加速 同时我也在做一个AVX2的优化 所以不久后我将发布一个RGB转灰度图算法优化的升级版 尝试触摸这一
  • 华为手机上的网上邻居怎么用_华为手机如何无线连接电脑

    不少朋友都会使用手机作为猫无线上网 那你知道如何用华为手机连接电脑3G上网 下面是小编给大家整理的一些有关华为手机连接电脑的方法 希望对大家有帮助 华为手机连接电脑的方法首先要确保已经安装了华为手机的驱动 接着在电脑的网上邻居那里点击右键
  • 浅谈对集群、分布式、分布式集群、微服务的理解

    我认为集群是个物理形态 分布式是个工作方式 分布式其实也是物理形态 这里相比较而言的 当集群中的服务器都做同样的事情时 集群就是一个集群 当集群中的服务器各司其职时 他就变成了分布式 所以说分布式中的每一个节点都可以是集群 但是集群并不一定
  • ES6的迭代器与迭代协议Symbol.iterator

    前言 ES6新增了两个协议 可迭代协议 对象必须具有Symbol Iterator属性 属性值为一个函数 当这个对象被迭代时 就会调用该函数 返回一个迭代器 迭代器协议 描述了迭代器对象的具体规则 迭代器 迭代器 它是用于访问集合类的标准访
  • 如何解决pip更新问题.WARNING: You are using pip version 19.2.3, however version 19.3.1 is available.

    出现如图所示 当直接输入python m pip install upgrade pip更新还报错的时候 输入命令 python m pip install pip 结果如图所示 亲测有效
  • mysql注解参数_MySQL主从复制参数注解

    MySQL主从复制参数注解 master所有参数 1 log bin mysql bin 1 控制master的是否开启binlog记录功能 2 二进制文件最好放在单独的目录下 这不但方便优化 更方便维护 3 重新命名二进制日志很简单 只需
  • String的intern()方法浅析

    简介 String intern 方法是一种手动将字符串加入常量池中的native方法 原理如下 如果在当前类的常量池中存在与调用intern 方法的字符串等值的字符串 就直接返回常量池中相应字符串的引用 否则在常量池中复制一份该字符串 J