58从零开始学Java之String字符串常量池和intern方法

news2024/12/25 23:52:25

作者:孙玉昌,昵称【一一哥】,另外【壹壹哥】也是我哦

千锋教育高级教研员、CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者

前言

在之前的文章中,壹哥给大家介绍了String字符串的不可变性及其实现原理,其中给大家提到了字符串常量池的概念。那么什么是常量池?String字符串与常量池有什么关系?常量池中存储的内容有什么特点?要想搞清楚这些问题,壹哥还得再利用一篇文章给大家唠唠字符串常量池及String#intern()方法的作用。

------------------------------------------------前戏已做完,精彩即开始----------------------------------------------

全文大约【2300】字,不说废话,只讲可以让你学到技术、明白原理的纯干货!本文带有丰富的案例及配图视频,让你更好地理解和运用文中的技术概念,并可以给你带来具有足够启迪的思考......

配套开源项目资料

Github:

GitHub - SunLtd/LearnJava

Gitee:

一一哥/从零开始学Java

一. 常量池简介

1. 基本概念

常量池是堆中的一块存储区域,用于存储显式的String、float、Integer等数据。这是一个特殊的共享区域,开发时不需要在内存中经常改变的数据,都可以放在这里进行共享。JDK 7及其之前的常量池是在方法区中,从Java8之后,常量池存放到了堆中。

为了让大家更好地理解常量池的作用,壹哥给大家分析一下String字符串的内存分配。

2. 实验案例

我们先来编写一行代码,如下所示:

//String对象创建
String s = new String("xyz");

这个代码很简单,就一行代码!那么问题来了,这行代码中几个对象的内存分配是如何的?接下来壹哥就给大家把这段代码的内存分区绘制一下(本案例开发环境是基于JDK8)。

3. 内存分配(重点)

String s = new String("xyz"); 这行代码中,s是String类型的变量,不是对象!‘xyz’是字符串对象,new String("xyz")也是一个对象,那么它们几个的内存划分在JDK8的环境中,如下图所示:

根据上图,壹哥给大家分析一下上述代码的内存分配情况,如下所示:

  1. 当JVM在编译阶段加载读取到“xyz”的时候,首先会检查堆中的String常量池,也就是常量缓冲区。检查是否已经有了"xyz"常量对象,如果有,则不会再次创建"xyz"常量对象,并直接返回该字符串的引用地址;如果没有,则创建一个"xyz"常量对象,并为该对象分配一个内存地址002返回;
  2. 当JVM在运行阶段加载读取到new关键字的时候,JVM会在堆中为其创建一个对象,即new String(),并为其分配内存地址001,而堆中这个对象的内容是上面"xyz"常量对象的引用地址002,换句话说这个堆中存的就是常量池中"xyz"的引用地址002;
  3. 最后,s 是对当前堆中001号对象的一个地址引用,s本身不是一个对象,s只是一个String类型的变量而已!

二. intern()方法(重点)

了解了常量池的内容之后,接下来请大家再跟着壹哥来看看String的intern()方法,这个方法很重要,请大家记住哦。

/**
     * Returns a canonical representation for the string object.
     * <p>
     * A pool of strings, initially empty, is maintained privately by the
     * class {@code String}.
     * <p>
     * When the intern method is invoked, if the pool already contains a
     * string equal to this {@code String} object as determined by
     * the {@link #equals(Object)} method, then the string from the pool is
     * returned. Otherwise, this {@code String} object is added to the
     * pool and a reference to this {@code String} object is returned.
     * <p>
     * It follows that for any two strings {@code s} and {@code t},
     * {@code s.intern() == t.intern()} is {@code true}
     * if and only if {@code s.equals(t)} is {@code true}.
     * <p>
     * All literal strings and string-valued constant expressions are
     * interned. String literals are defined in section 3.10.5 of the
     * <cite>The Java&trade; Language Specification</cite>.
     *
     * @return  a string that has the same contents as this string, but is
     *          guaranteed to be from a pool of unique strings.
     */
    public native String intern();

从上面的源码注释中我们可以知道,intern()是由C语言实现的native底层方法,用于从String缓存池中获取一个与该字符串内容相同的字符串对象。当这个intern()方法被执行的时候,如果缓存池中已经有这个String内容,则直接从这个缓存池中获取该String内容对象;如果缓存池中没有这个String内容对象,则把这个String内容对象放到缓存池中,并返回这个字符串对象的引用现在我们知道了intern()方法的功能,但是该方法的底层原理是什么样的呢?接下来 壹哥 给结合一段代码案例,给各位详细说一下:

//常量池与堆的关系
String str1="yiyige";
String str2=new String("yiyige");
System.out.println("str1==str2的结果==> " +(str1==str2));

String str3 = str2.intern();
System.out.println("str1==str3的结果==> " +(str1==str3));

执行结果如下图所示:

intern()方法的底层原理如下(重点):

Java专门为String类设计了一个缓存池intern pool,intern pool是在方法区中的一块特殊存储区域,当我们通过 String str="yiyige" 这样的方式来构造一个新的字符串时,String类会优先在缓存池中查找是否已经存在内容相同的String对象。如果有则直接返回该对象的地址引用,如果没有就会构造一个新的String对象,然后放进缓存池,再返回该字符串的地址引用。因此,即使我们构造一万个String str = "yiyige",但实际上得到的都是同一个地址引用,这样就避免了很多不必要的空间开销。注意:intern池不适用new String("yiyige")的构造形式!

注意:

因为字符串常量池存放位置发生了变化,String类对intern()方法也进行了一些修改:

JDK 6 版本中执行intern()方法时,首先会判断字符串常量池中是否存在该字符串字面量,如果不存在则拷贝一份字符串字面量存放到常量池中,最后返回该字符串字面量的唯一引用。如果发现字符串常量池中已经存在,则直接返回该字符串字面量的唯一引用。

JDK 7 以后执行intern()方法时,如果发现字符串常量池中不存在该字符串字面量,则不会再拷贝一份字面量,而是拷贝字面量对应堆中的一个地址引用,然后返回这个引用。

现在我们知道了,原来当一个String对象被创建时,如果发现当前String对象已经存在于String Pool中了,就会返回一个已存在的String对象引用而不会新建一个对象。比如以下代码只会在常量池中创建一个String对象。

String str1 = "yiyige"; 
String str2 = "yiyige";

创建过程如下图所示:

如果一个String是可变的,当改变了A引用指向的String时,可能就会导致其他的B引用得到错误的值,所以Sting就被设计为不可变的。String底层主要是使用intern缓存池将字符串缓存起来,同时允许把一个String字符串的地址赋值给多个String变量来引用,这样就可以保证多个变量安全地共享同一个对象。如果Java中的String对象可变的话,一个字符串引用的操作改变了对象的值,那么其他的变量就会受到影响。

另外,关于String源码的解读,及不可变性的相关面试题,壹哥在自己的高薪面试题专栏中有过非常详细地讲解,如果你想了解更多,请参考如下链接:

《高薪程序员&面试题精讲系列06之String s=new String(“xyz“)中产生了几个对象?》

三. 结语

至此,壹哥就把字符串相关的一些常规原理性知识点,给大家讲解梳理完毕了。当然,关于String原理性的面试题还有很多,受篇幅所限,壹哥就不再说这么多了,欢迎大家订阅我的《高薪程序员&面试题精讲系列》。与本文配套的视频链接如下:

External Player - 哔哩哔哩嵌入式外链播放器

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Springboot 配置使用 Kafka

Springboot 配置使用 Kafka 前言一、Linux 安装 Kafka二、构建项目三、引入依赖四、配置文件生产者yml 方式Config 方式 消费者yml 方式Config 方式 五、开始写代码生产者发送成功回调和异常处理 消费者接收异常处理 七、开始测试测试普通单条消息测试消费者异常处理测试延时消…

【JAVA基础——final关键字】

JAVA基础 final 关键字 文章目录 JAVA基础概述final修饰类final修饰方法final修饰变量非final类内 final修饰的方法和变量可以被继承类调用 概述 在 Java 中&#xff0c;final 是一个关键字&#xff0c;用于修饰类、方法和变量。 final 类&#xff1a; 不可被继承。final 常…

Linux用户与组管理(02)(七)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、批量创建 二、修改属性 三、密码设置 四、删除 总结 前言 今天学习的是上次剩余的用户组的内容&#xff0c;也是相对于刚学习Linux系统比较重要的部分&#x…

人民日报--全站图文数据库信息采集

支持2020-2023所有图文数据采集 #!/usr/bin/python3 # -*- coding:utf-8 -*- import requests import re from lxml import etree from sdk.utils.util_decorate import retryretry(retry3,sleep5) def get_html(url):response requests.get(url)response.encoding "u…

Leetcode刷题笔记--Hot31-40

1--颜色分类&#xff08;75&#xff09; 主要思路&#xff1a; 快排 #include <iostream> #include <vector>class Solution { public:void sortColors(std::vector<int>& nums) {quicksort(nums, 0, nums.size()-1);}void quicksort(std::vector<int…

Java虚拟机

文章目录 JVM运行时数据区域HotSpot虚拟机对象探秘实战&#xff1a;OutOfMemoryError异常 JVM 运行时数据区域 HotSpot虚拟机对象探秘 实战&#xff1a;OutOfMemoryError异常

01-6W2H方法

前言&#xff1a;6W2H法是我们制定策略时的黄金策略&#xff0c;并有不同的衍生版本&#xff0c;比如5W1H、3W1H等等&#xff0c;都是结合实际情况进行的剪裁运用。通过6W2H思想方法来进行研发管理以及问题分析&#xff0c;具备清晰的思路。 脑图&#xff1a;//参考

【Flutter】Flutter 使用 flex_color_scheme 创建美观的 Material Design 主题

【Flutter】Flutter 使用 flex_color_scheme 创建美观的 Material Design 主题 文章目录 一、前言二、FlexColorScheme 简介三、开始使用 FlexColorScheme四、实际业务中的应用五、FlexColorScheme 的高级功能六、完整实际业务代码示例七、总结 一、前言 今天&#xff0c;我想…

【算法刷题之字符串篇】

目录 1.leetcode-344. 反转字符串&#xff08;1&#xff09;方法&#xff1a;双指针 2.leetcode-541. 反转字符串 II&#xff08;1&#xff09;方法一&#xff1a;模拟&#xff08;2&#xff09;方法二&#xff1a;双指针 3.leetcode-剑指 Offer 05. 替换空格&#xff08;1&…

【大数据知识】大数据平台和数据中台的定义、区别以及联系

数据行业有太多数据名词&#xff0c;例如大数据、大数据平台、数据中台、数据仓库等等。但大家很容易混淆&#xff0c;也很容易产生疑问&#xff0c;今天我们就来简单聊聊大数据平台和数据中台的定义、区别以及联系。 大数据平台和数据中台的定义 大数据平台&#xff1a;一个…

AUTOSAR系列专题--诊断模块(下)

往期小怿向各位小伙伴介绍了&#xff0c;文章内容过多分为了两期&#xff0c;本期为大家介绍《AUTOSAR模块之诊断篇&#xff08;下&#xff09;》。 目录 1.概述 2.DCM 3.DEM 4.FIM 5.结语 点击查看前文&#xff1a;AUTOSAR系列专题--诊断模块&#xff08;上&#xff09;…

设备维护管理软件哪家好?设备巡检系统对企业经营管理有什么好处?

随着时代的不断进步&#xff0c;科学技术的飞速发展以及自动化水平的持续提高&#xff0c;设备维护保养工作在日常工作生产中扮演着至关重要的角色。然而&#xff0c;在实际生产中&#xff0c;由于对设备性能和保养规程的不熟悉&#xff0c;常常出现误操作、保养不到位或无法及…

如何修改字符串内容?

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;浅谈Java &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; String 1. 修改字符串2. StringBuilder和…

bpmnjs Properties-panel拓展(属性设置篇)

最近有思考工作流相关的事情&#xff0c;绘制bpmn图的工具认可度比较高的就是bpmn.js了&#xff0c;是一个基于node.js的流程图绘制框架。初始的框架只实现了基本的可视化&#xff0c;想在xml进行客制化操作的话需要拓展&#xff0c;简单记录下几个需求的实现过程。 修改基础 …

leetcode 516. 最长回文子序列

2023.8.27 本题依旧使用dp算法做&#xff0c;可以参考 回文子串 这道题。dp[i][j]定义为&#xff1a;子串s[i,j] 的最长回文子串。 直接看代码: class Solution { public:int longestPalindromeSubseq(string s) {vector<vector<int>> dp(s.size(),vector<int&…

JVM知识点(一)

1、JVM基础概念 &#xff08;1&#xff09;JVM、JRE、JDK JRE&#xff1a;JVM基本类库组成的运行环境就是JRE。JVM自己是无法完成一次编译&#xff0c;处处运行的&#xff0c;需要有一个基本类库告诉JVM如何操作运行&#xff0c;如如何操作文件&#xff0c;连接网络等&#x…

四川玖璨电子商务有限公司:短视频运营表格

随着互联网的飞速发展和用户对内容需求的不断增加&#xff0c;短视频运营成为了当前互联网领域的一大热门。短视频作为一种具有高度吸引力和传播力的内容形式&#xff0c;成为各大平台争相追逐和竞争的热点。 然而&#xff0c;短视频运营并非一项简单的任务。为了能够在激烈的…

HOOPS Exchange如何实现3D模型格式转换?

HOOPS Exchange是一个专业的3D数据转换工具包&#xff0c;用于处理各种不同格式的3D模型数据。它提供了高效、精确的转换和处理功能&#xff0c;让开发者能够在不同的3D软件和环境之间无缝交换模型数据。 HOOPS Exchange将模型加载到标准化数据结构中&#xff0c;可以查询该数…

Android Update Engine 分析(二十一)Android A/B 更新过程

0. 背景 早期 Android A/B 系统升级在 Android 7.1 版本推出时&#xff0c;参考文档十分有限&#xff0c;也就是 Android 官方大概有两三个页面介绍文档。 我的第一篇 A/B 系统分析文章《Android A/B System OTA分析&#xff08;一&#xff09;概览》从总体上介绍了什么是 A/…

全面解析MES系统中的车间退料管理

一、车间退料管理的定义&#xff1a; 车间退料是指在生产过程中&#xff0c;将不合格或多余的物料、半成品或成品从车间环节返还到供应链的过程。车间退料管理则是指对这一退料过程进行规范化、系统化的管理和跟踪。 二、车间退料管理的流程&#xff1a; 1. 退料申请&#xf…