⛳ String 字符串的存储原理及常用方法

目录

  • ⛳ String 字符串的存储原理及常用方法
    • 🏭 一,`String` 对象介绍
    • 🚜二,`String` 的内存结构
      • 📢 2.1,创建字符串
        • 🎉 创建字符串的情况:
            • 空值创建:
            • 非空值创建:
          • `String str1 = "abc";` 与 `String str2 = new String('abc');`的区别
          • 直接创建和`new`创建字符串的JVM存储结构
      • 🎨 2.2,拼接字符串
        • **📐 案例一:**
        • 💖 案例二:
    • 🎁 三,`String` 类常用的方法

⛳ String 字符串的存储原理及常用方法

🏭 一,String 对象介绍

  • String类: 代表字符串。 Java 程序中的所有字符串字面值(如 “abc” )都作为此类的实例实现。
  • String是一个final类,代表不可变的字符序列。
  • 字符串是常量,用双引号引起来表示。 它们的值在创建之后不能更改。
  • String对象的字符内容是存储在一个字符数组value[]中的。
public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {/** The value is used for character storage. */private final char value[];/** Cache the hash code for the string */private int hash; // Default to 0

🚜二,String 的内存结构

基本数据类型和引用类型的区别主要在于基本数据类型是分配在栈上的,而引用类型是分配在堆上的。因为String是一个类,所以Java种的字符串String属于引用数据类型。

:由JVM分配区域,用于保存线程执行的动作和数据引用。栈是一个运行的单位,Java中一个线程就会相应有一个线程栈与之对应。

:由JVM分配的,用于存储对象等数据的区域。

常量池 :在堆中分配出来的一块存储区域,用于存储显式 的String,float或者integer.例如String str=“abc”; abc这个字符串是显式声明,所以存储在常量池。

JDK6 的版本,常量池在永久代(PermGen)中分配;

JDK7 的版本,常量池在堆内存 Heap 中分配;

本文的内存分配图都是基于 JDK7以上的版本

📢 2.1,创建字符串

  • 下面的代码,在JVM的存储方式
String s1 = "abc";  // 字面量的定义方式
String s2 = "abc";
s1 = "hello";

a

  • intern() 方法

    • s2.intern()是一个Java中的方法,用于将字符串对象添加到字符串常量池中。在Java中,字符串常量池是一个存储字符串对象的特殊区域,它的目的是提高字符串的重用性和比较效率。
      当调用s2.intern()方法时,它会首先检查字符串常量池中是否存在与s2值相等的字符串对象。如果存在,则返回常量池中的对象;如果不存在,则将s2添加到常量池中,并返回该新的常量池对象的引用。
    • 这种方法通常用于优化字符串的内存使用和比较操作。通过将字符串对象添加到常量池中,可以减少内存中重复字符串的数量,并且可以使用==运算符来比较字符串的引用是否相等,而不需要比较字符串的内容。
        @Testpublic void test01(){String s1 = "hello";String s2 = new String("hello");String internS2 = s2.intern();System.out.println(s1 == s2);  // falseSystem.out.println(s1 == internS2);  // true}
    

    说明:创建了一个字符串s1,并直接将其赋值为"Hello"。然后,我们使用关键字new创建了另一个字符串对象s2,它的值也是"Hello",但是它是通过构造函数创建的,因此它在内存中的地址不同于s1

    接下来,我们调用s2.intern()方法,将s2添加到字符串常量池中,并将返回的常量池对象引用赋值给internedS2变量。

    后,我们使用==运算符来比较s1s2internedS2三者之间的引用关系。由于s1指向字符串常量池中的"Hello"对象,而internedS2也指向同一个对象,所以s1 == internedS2表达式的结果为true。而s1s2是两个不同的对象,因此s1 == s2表达式的结果为false

    这个示例说明了s2.intern()方法的作用,它将字符串对象添加到字符串常量池中,使得多个字符串对象可以共享同一个引用,从而节省内存并提高比较效率。

🎉 创建字符串的情况:

空值创建:
  1. String s;String s = null;

    String1.drawio

  2. String s = "";初始化字符串常量(在常量池中有一个空的数组)

    String2.drawio

  3. String s = new String(); (String类中的 value属性指向一个堆内存中的空数组)Strng3.drawio

  4. String s = new String("");

    String4.drawio

非空值创建:
  1. String s = 'abc';

    String2-1.drawio

  2. String s = new String("abc");

    String2-2.drawio

  3. char[] arr = {'a','b'};String s = new String(arr);(把arr的字符数组,复制一份存到常量池里)

    String2-3.drawio2

  4. char[] arr = {'a','b','c','d','e'};String s = new String(arr,0,3);(截取arr字符数组的 [0,3) 的字符,复制到常量池中)

    String2-4.drawio

String str1 = "abc";String str2 = new String('abc');的区别
  • 字符串常量存储在字符串常量池中,目的是共享。
  • 字符串非常量对象存储在堆中。

String-null-new.drawio

直接创建和new创建字符串的JVM存储结构

分析下面代码的JMM结构:

public void test(){String s1 = "javaEE";String s2 = "javaEE";String s3 = new String("javaEE");String s4 = new String("javaEE");System.out.println(s1 == s2); // trueSystem.out.println(s1 == s3); // falseSystem.out.println(s1 == s4); // falseSystem.out.println(s3 == s4); // falses4 = new String("python");
}

结构图:

String-structure.drawio

🎨 2.2,拼接字符串

下面我们通过两个案例来看字符串拼接的存储结构。

  • intern()方法;
  • 例 s4,s41 : 在有变量参与的表达式,其中一个常量(如:“world”, “123”),如果常量池中已经存在,则直接引用常量池中的常量(“world”),如果不存在,则把常量(“123”)先存放到常量池中,再进行计算引用。

📐 案例一:

    @Testpublic void test2(){String s1 = "hello";String s2 = "world";String s3 = "hello" + "world";String s4 = s1 + "world";String s41 = s1 + "123";String s5 = s1 + s2;String s6 = (s1 + s2).intern();System.out.println(s3 == s4);  // falseSystem.out.println(s3 == s5);  // falseSystem.out.println(s4 == s5);  // falseSystem.out.println(s3 == s6);  //  trueSystem.out.println(s41);       // hello123}

JMM内存结构图:

String_joint.drawio

javap -v TestDemo.class反编译的结果:

image-20230803135016871

💖 案例二:

循环的方式生成字符串

  • 每循环一次,s1 的引用更新一次。
  • 常量池中只有字符串 “0”;
  • 其他生成的字符串都是在堆里生成的;
        String s1 = "0";for (int i = 1; i <= 5 ; i++) {s1 += i;}System.out.println(s);

JMM内存结构图:

String_joint-01.drawio

javap -v TestDemo.class反编译结果:

image-20230804140239389

🎁 三,String 类常用的方法

  • int length():返回字符串的长度:return value.length

  • char charAt(int index):返回某索引处的字符return value[index]

  • boolean isEmpty():判断是否是空字符串:return value.length == 0

  • String toLowerCase():使用默认语言环境,将String中的所有字符转换为小写

  • String toUpperCase():使用默认语言环境,将String中的所有字符转换成大写

  • String trim():返回字符串的副本,忽略前导空白和尾部空白

  • boolean equals(Object obj):比较字符串的内容相同

  • boolean equalsIgnoreCase(String anotherString):与equals方法类似,忽略大小写

  • String concat(String str):将指定字符串连接到此字符串的结尾。等价于用 “+”

  • int compareTo(String anotherString):比较两个字符串的大小

    • compareTo(String anotherString)的源码

          public int compareTo(String anotherString) {int len1 = value.length;int len2 = anotherString.value.length;int lim = Math.min(len1, len2);char v1[] = value;char v2[] = anotherString.value;int k = 0;while (k < lim) {char c1 = v1[k];char c2 = v2[k];if (c1 != c2) {return c1 - c2;}k++;}return len1 - len2;}
      
  • String substring(int beginIndex):返回一个新的字符串,它是此字符串的beginIndex开始截取到最后的一个字符串

  • String substring(int beginIndex, int endIndex):返回一个新字符串,它是此字符串从biginIndex开始截取到endIndex(不包含) 的字符串。

  • boolean contains(CharSequence s):当且仅当此字符串包含指定的char值序列时,返回true

  • int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引

  • int indexOf(String str, int fromIndex):返回指定字符串在此字符串中第一出现的索引,从指定索引开始

  • int lastIndexOf(String str):返回指定字符串在此字符串中最右边出现处的索引

  • int lastIndexOf(String str, int fromIndex):返回指定字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。注indexOf()和lastIndexOf()方法如果未找到都是返回 -1;

  • boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束

  • boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始

  • boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始

  • String replace(char oldChar, char newChar) 返回一个新的字符串, 它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。

  • String replace(CharSequence target, CharSequence replacement) 使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。

  • String replaceAll(String regex, String replacement) 使 用 给 定 的replacement 替换此字符串所有匹配给定的正则表达式的子字符串。

  • String replaceFirst(String regex, String replacement) 使 用 给 定 的replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。

  • boolean matches(String regex) 告知此字符串是否匹配给定的正则表达式。

  • String[] split(String regex) 根据给定正则表达式的匹配拆分此字符串。

  • String[] split(String regex, int limit) 根据匹配给定的正则表达式来拆分此字符串, 最多不超过limit个, 如果超过了, 剩下的全部都放到最后一个元素中。

测试用例:

    @Testpublic void test4() {// 定义一个字符串对象String s = "helloworld";// int length():获取字符串的长度。System.out.println("s.length:" + s.length());System.out.println("----------------------");// char charAt(int index):获取指定索引位置的字符System.out.println("charAt:" + s.charAt(0));System.out.println("----------------------");// int indexOf(int ch):返回指定字符在此字符串中第一次出现处的索引。System.out.println("indexOf:" + s.indexOf('l'));System.out.println("----------------------");// int indexOf(String str):返回指定字符串在此字符串中第一次出现处的索引。System.out.println("indexOf:" + s.indexOf("owo"));System.out.println("----------------------");// int indexOf(int ch,int fromIndex):返回指定字符在此字符串中从指定位置后第一次出现处的索引。System.out.println("indexOf:" + s.indexOf('l', 4));System.out.println("indexOf:" + s.indexOf('k', 4)); // -1System.out.println("indexOf:" + s.indexOf('l', 40)); // -1System.out.println("----------------------");// 自己练习:int indexOf(String str,int// fromIndex):返回指定字符串在此字符串中从指定位置后第一次出现处的索引。// String substring(int start):从指定位置开始截取字符串,默认到末尾。包含start这个索引System.out.println("substring:" + s.substring(5));System.out.println("substring:" + s.substring(5,7)); //开始时5,结束是7,不包括7System.out.println("substring:" + s.substring(0));System.out.println("----------------------");// String substring(int start,int// end):从指定位置开始到指定位置结束截取字符串。包括start索引但是不包end索引System.out.println("substring:" + s.substring(3, 8));System.out.println("substring:" + s.substring(0, s.length()));String s3 = "  abc 123  ";System.out.println(s3.trim().length()); //去掉前后两端的空格String s4 = "a,b,c,d,e,123";String[] s5 =  s4.split(",");for (int i = 0; i < s5.length; i++) {System.out.println(s5[i]);}}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot + Docker 实现一次构建到处运行

一、容器化部署的好处 Docker 作为一种新兴的虚拟化方式&#xff0c;它可以更高效的利用系统资源&#xff0c;不需要进行硬件虚拟以及运行完整操作系统等额外开销。 传统的虚拟机技术启动应用服务往往需要数分钟&#xff0c;而 Docker 容器应用&#xff0c;由于直接运行宿主内…

Linux系统jenkins+newman+postman持续集成环境搭建

1、首先安装nodejs 下载nodejs压缩包&#xff0c;下载地址&#xff1a;nodejs官网下载 建议不用下载最新的&#xff0c;我这里用的是推荐的v12.18版本 下载和解压命令 wget https://nodejs.org/dist/v12.18.3/node-v12.18.3-linux-x64.tar.xz解压安装包&#xff08;记得没有z&…

【实践篇】推荐算法PaaS化探索与实践 | 京东云技术团队

作者&#xff1a;京东零售 崔宁 1. 背景说明 目前&#xff0c;推荐算法部支持了主站、企业业务、全渠道等20业务线的900推荐场景&#xff0c;通过梳理大促运营、各垂直业务线推荐场景的共性需求&#xff0c;对现有推荐算法能力进行沉淀和积累&#xff0c;并通过算法PaaS化打造…

数实融合 产业共创 | 竹云受邀出席“2023湾区数字科技50人论坛”

7月29日&#xff0c;“2023湾区数字科技50人论坛”在深圳湾科技生态园圆满举行&#xff01;本届论坛由深圳市科学技术协会指导&#xff0c;中国鲲鹏产业源头创新中心、湾盟产业创新服务中心主办&#xff0c;深圳市金融攻关基地、广东赛迪工业和信息化研究院、香港科技大学深港协…

NetMizer 日志管理未授权访问+FTP登录

漏洞描述 北京灵州网络技术有限公司NetMizer日志管理系统存在目录遍历漏洞&#xff0c;由于 /data 控制不严格&#xff0c;攻击者可利用该漏洞获取敏感信息。 免责声明 技术文章仅供参考&#xff0c;任何个人和组织使用网络应当遵守宪法法律&#xff0c;遵守公共秩序&#…

pytorch学习——卷积神经网络——以LeNet为例

目录 一.什么是卷积&#xff1f; 二.卷积神经网络的组成 三.卷积网络基本元素介绍 3.1卷积 3.2填充和步幅 3.2.1填充&#xff08;Padding&#xff09; 填充是指在输入数据周围添加额外的边界值&#xff08;通常是零&#xff09;&#xff0c;以扩展输入的尺寸。填充可以在卷…

生鲜蔬果小程序的完整教程

随着互联网的发展&#xff0c;线上商城成为了人们购物的重要渠道。其中&#xff0c;小程序商城在近年来的发展中&#xff0c;备受关注和青睐。本文将介绍如何使用乔拓云网后台搭建生鲜果蔬配送小程序&#xff0c;并快速上线。 首先&#xff0c;登录乔拓云网后台&#xff0c;进入…

C#+WPF上位机开发(模块化+反应式)

在上位机开发领域中&#xff0c;C#与C两种语言是应用最多的两种开发语言&#xff0c;在C语言中&#xff0c;与之搭配的前端框架通常以QT最为常用&#xff0c;而C#语言中&#xff0c;与之搭配的前端框架是Winform和WPF两种框架。今天我们主要讨论一下C#和WPF这一对组合在上位机开…

无人机巢的作用及应用领域解析

无人机巢作为无人机领域的创新设备&#xff0c;不仅可以实现无人机的自主充电和电池交换&#xff0c;还为无人机提供安全便捷的存放空间。为了帮助大家更好地了解无人机巢&#xff0c;本文将着重解析无人机巢的作用和应用领域。 一、无人机巢的作用 无人机巢作为无人机技术的重…

【RabbitMQ】golang客户端教程2——工作队列

任务队列/工作队列 在上一个教程中&#xff0c;我们编写程序从命名的队列发送和接收消息。在这一节中&#xff0c;我们将创建一个工作队列&#xff0c;该队列将用于在多个工人之间分配耗时的任务。 工作队列&#xff08;又称任务队列&#xff09;的主要思想是避免立即执行某些…

opencv-38 形态学操作-闭运算(先膨胀,后腐蚀)cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)

闭运算是先膨胀、后腐蚀的运算&#xff0c;它有助于关闭前景物体内部的小孔&#xff0c;或去除物体上的小黑点&#xff0c;还可以将不同的前景图像进行连接。 例如&#xff0c;在图 8-17 中&#xff0c;通过先膨胀后腐蚀的闭运算去除了原始图像内部的小孔&#xff08;内部闭合的…

案例实践:小红书APP出现闪退问题,接口测试怎么做?(二)

Postman实现接口功能测试 新增货品接口实战 1、填写接口请求4要素&#xff1a; 由于货品新增接口文档找不到接口请求4要素中的&#xff1a;请求方法、请求地址和请求头&#xff0c;故&#xff0c;使用Fiddler抓包获取&#xff0c;获取结果如下&#xff1a; 1&#xff09;请求…

Zebec APP:构建全面、广泛的流支付应用体系

目前&#xff0c;流支付协议 Zebec Protocol 基本明确了生态的整体轮廓&#xff0c;它包括由其社区推动的模块化 Layer3 构架的公链 Nautilus Chain、流支付应用 Zebec APP 以及 流支付薪酬工具 Zebec payroll 。其中&#xff0c;Zebec APP 是原有 Zebec Protocol 的主要部分&a…

【逗老师的PMP学习笔记】4、项目整合管理

目录 一、制定项目章程1、制定项目章程的整体输入、输出和工具技术2、输入2.1、输入-商业文件2.2、输入-协议2.3、输入-事业环境因素组织过程资产 3、工具与技术3.1、专家判断3.2、数据收集3.3、人际关系与团队技能3.4、会议 4、输出4.1、输出-项目章程4.2、输出-假设日志 二、…

61 # http 数据处理

node 中的核心模块 http 可以快速的创建一个 web 服务 const http require("http"); const url require("url");// req > request 客户端的所有信息 // res > respone 可以给客户端写入数据 const server http.createServer();server.on("r…

【前端知识】React 基础巩固(四十二)——React Hooks的介绍

React 基础巩固(四十二)——React Hooks的介绍 一、为什么需要Hook? Hook 是 React 16.8 的新增特性&#xff0c;它可以让我们在不编写class的情况下使用state以及其他的React特性&#xff08;比如生命周期&#xff09;。 class组件 VS 函数式组件&#xff1a; class的优势…

让Python点亮你的世界:打造专业级编程环境的必备步骤

文章目录 初识pythonpython的安装win系统Linux系统&#xff08;centos7&#xff09; 第一个Python程序常见问题 Python解释器Python开发环境PyCharm的基础使用创建项目修改主题修改默认字体和大小汉化插件翻译软件常用快捷键 初识python Python语言的起源可以追溯到1989年&…

基于ARM+FPGA的驱控一体机器人控制器设计

目前市场上工业机器人&#xff0c;数控机床等多轴运动控制系统普遍采用运动控制器加 伺服驱动器的分布式控制方式。在这种控制方式中&#xff0c;控制器一方面完成人机交互&#xff0c;另 一方面进行 NC 代码的解释执行&#xff0c;插补运算&#xff0c;继而将计算出来的位…

jmeter之接口测试(http接口测试)

基础知识储备 一、了解jmeter接口测试请求接口的原理 客户端--发送一个请求动作--服务器响应--返回客户端 客户端--发送一个请求动作--jmeter代理服务器---服务器--jmeter代理服务器--服务器 二、了解基础接口知识&#xff1a; 1、什么是接口&#xff1a;前端与后台之间的…

云计算——常见集群策略

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​ 目录 前言 一.什么是集群 二.集群策略 1.虚拟机HA 实现虚拟机高可用性通常涉及以下关键…