揭秘:Java字符串对象的内存分布原理

先来看看下面寄到关于String的真实面试题,看看你废不废?

在这里插入图片描述

String str1 = "Hello";
String str2 = "Hello";
String str3 = new String("Hello");
String str4 = new String("Hello");System.out.println(str1 == str2); // true or false?
System.out.println(str1.equals(str2)); // true or false?
System.out.println(str1 == str3); // true or false?
System.out.println(str1.equals(str3)); // true or false?
System.out.println(str3 == str4); // true or false?

如果要正确回答上面几个面试题,不深入理解String类型的内存原理是不行的,本篇的唯一目的就是言简意赅、深入浅出的梳理String类型的底层原理。

一,字符串存储的内存原理

1,字面量声明字符串对象

String name = "Java";

如上,以字面量声明的字符串String对象存储在堆内存中,而其内容(字符数组)则保存在字符串常量池中(从JDK 7开始,字符串常量池被移到了堆中)。

在这里插入图片描述

结合上图,对于代码String name = "Java";,创建的字符串对象的内存分布如下:

  • String是引用类型,所以变量name存储的是字符串对象的地址值0xefd,指向常量池某一条记录,如箭头①
  • ②常量池是HashTable,存储的是字符串对象的地址,如箭头②
  • ③String内部使用一个名为valuebyte数组存储字符串的,显然变量value是引用类型,所以其值也是地址,指向一个byte数组对象,如上图箭头③
    在这里插入图片描述

那么问题来了,两个字面量相等的变量的内存分布是怎样的呢?

String name = "Java";
String name2 = "Java";

在这里插入图片描述

当创建一个String时,如果该字符串已经存在于常量池中,则直接引用该字符串;否则,会在常量池中创建一个新的字符串实例,并返回对该实例的引用。

所以,如上图所示,因为这两个变量都是以字面量声明的,且字符串值都是“Java”,所以变量namename2会指向同一个地址。

2,构造函数声明字符串对象

String name = new String("Java");

如上,当以构造函数声明字符串对象时,与字面量最大的不同是,创建的字符串对象不会保存在字符串常量池中,字符串String对象存储在堆内存中,其内存分布如下图所示:

在这里插入图片描述

类似的问题,创建两个值一样的对象,其内存是怎么分布的呢?

String name = new String("Java");
String name2 = new String("Java");

对于上面代码,如下图所示,会创建两个完全不同的字符串对象。
在这里插入图片描述
从上面可以看出,用字面量声明对象,字符串相同时,可以复用字符串对象,有更高的内存利用率。所以,最佳实践是使用字面量声明字符串对象。

二,面试题分析

对于文章开头的面试题:

String str1 = "Hello";
String str2 = "Hello";
String str3 = new String("Hello");
String str4 = new String("Hello");System.out.println(str1 == str2); // true or false?
System.out.println(str1.equals(str2)); // true or false?
System.out.println(str1 == str3); // true or false?
System.out.println(str1.equals(str3)); // true or false?
System.out.println(str3 == str4); // true or false?

对象str1和str2是通过字面量创建的,这两个变量在字符串常量池的作用下,指向同一个字符串对象,所以:

System.out.println(str1 == str2); 
System.out.println(str1.equals(str2)); 

结果都是true

在这里插入图片描述

这里需要知道运算符 == 和 函数equals的区别:

  • 运算符 ==比较的是两个对象在内存中地址,即栈中变量存储的值
  • 函数equals会把内存中的字符串值取出来比较是否相同,如上例,比较的是字符串"Java"和"Java"是否相同

变量str3是通过构造函数创建的,所以不会通过常量池复用已经创建的对象,所以两个变量指向不同地址的对象,用运算符==比较的结果是false;但两个对象存储的字符串内容是相同的,用equals比较的结果是true

System.out.println(str1 == str3);
System.out.println(str1.equals(str3)); 

在这里插入图片描述

System.out.println(str3 == str4); 
System.out.println(str3.equals(str4)); 

因为对象str3和str4都是通过构造函数创建的,根据前面的分析,会创建两个不同的对象,所以,用运算符==比较的结果是false;但两个对象存储的字符串内容是相同的,用equals比较的结果是true
在这里插入图片描述

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

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

相关文章

Android 11 Audio strategy配置解析

在启动AudioPolicyService时,通过EngineBase的loadAudioPolicyEngineConfig函数去解析strategy配置。其调用流程如下 接下来就对loadAudioPolicyEngineConfig展开分析 1,解析volume标签 engineConfig::ParsingResult EngineBase::loadAudioPolicyEngine…

Pytorch Lighting 库的学习 mvsplat 的笔记

变量理解: context_image: 表示投影的 refrence image Epipolar Transformer vs Swin Transformer : 不同于 Pixel Splat 使用的是 Epipolar Transformer. MVspalt 使用的是 Swin Transformer, 但是作者在 Code 里面 也使用了 Epipolar Tran…

容器项目之前后端分离

容器化部署ruoyi项目 #需要的镜像nginx、java、mysql、redis、 #导入maven镜像、Java镜像和node镜像 docker load -i java-8u111-jdk.tar docker load -i maven-3.8.8-sapmachine-11.tar docker load -i node-18.20.3-alpine3.20.tar #拉取MySQL和nginx镜像 docker pull mysql…

echarts学习:基本使用和组件封装

前言 我在工作中使用echarts较少,这就导致每次使用时都要从头再来,这让我很头疼。因此我决心编写一系列文章将我参与工作后几次使用echarts所用到的知识记录下来,以便将来可以快速查阅。 一、基本使用 像我一样的新手,想要入门e…

PyCharm中快速搭建Python虚拟环境的指南

在 PyCharm 中创建一个新的 Python 虚拟环境可以帮助你为不同的项目管理不同的依赖包,避免版本冲突。以下是在 PyCharm 中创建虚拟环境的步骤: 打开或创建一个项目: 如果你还没有打开 PyCharm,首先打开它,然后选择“Open”打开一个…

【Java】还有人不懂继承?25 个 Case 包教包会

还有人不懂继承?25 个 Case 包教包会 1.Implement single inheritance2.Implement multilevel inheritance3.Implement hierarchical inheritance4.Override a base class method into a derived class5.Demonstrate the protected access specifier6.Create an Stu…

开发电商系统的技术选型

开发电商系统是一个复杂的任务,需要全面的技术选型来确保系统的稳定性、可扩展性和性能。本文将详细探讨在开发电商系统时涉及的各方面技术选型,包括架构设计、前端技术、后端技术、数据库选择、缓存策略、安全性、支付系统、日志和监控、以及自动化运维…

RN的安卓和iOS打包步骤(软件托管平台推荐)

安卓 官方中文网网址 步骤 1.在项目/android/app下面运行如下终端命令 keytool -genkeypair -v -storetype PKCS12 -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000<

《面试笔记》——MySQL终结篇30

三大范式&#xff1f; 第一范式&#xff1a;字段具有原子性&#xff0c;不可再分&#xff08;字段单一职责&#xff09; 第二范式&#xff1a;满足第一范式&#xff0c;每行应该被唯一区分&#xff0c;加一列存放每行的唯一标识符&#xff0c;称为主键&#xff08;都要依赖主…

10- Redis 键值对数据库是怎么实现的?

在开始将数据结构之前&#xff0c;先给介绍下 Redis 是怎样实现键值对&#xff08;key-value&#xff09;数据库的。 Redis 的键值对中的 key 就是字符串对象&#xff0c;而 value 可以是字符串对象&#xff0c;也可以是集合数据类型的对象&#xff0c;比如 List 对象&#xf…

Django序列化器中is_valid和validate

今天上班的时候分配了一个任务&#xff0c;是修复前端的一个提示优化&#xff0c;如下图所示&#xff1a; 按照以往的经验我以为可以直接在validate上进行校验&#xff0c;如何抛出一个异常即可 &#xff0c;例如&#xff1a; class CcmSerializer(serializers.ModelSerialize…

体验Photoshop:无需下载,直接在浏览器编辑图片

搜索Photoshop时&#xff0c;映入眼帘的是PS软件下载&#xff0c;自学PS软件需要多长时间&#xff0c;学PS软件有必要报班吗...PS软件的设计功能很多&#xff0c;除了常见的图像处理功能外&#xff0c;还涉及图形、文本、视频、出版等。不管你是平面设计师&#xff0c;UI/UX设计…

字节算法岗二面秒挂,效率真高。。。

节前&#xff0c;我们组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、今年参加社招和校招面试的同学。 针对大模型技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备面试攻略、面试常考点等热门话题进行了深入的讨论。 总结链接…

Servlet搭建博客系统

现在我们可以使用Servlet来搭建一个动态(前后端可以交互)的博客系统了(使用Hexo只能实现一个纯静态的网页,即只能在后台自己上传博客)。有一种"多年媳妇熬成婆"的感觉。 一、准备工作 首先创建好项目,引入相关依赖。具体过程在"Servlet的创建"中介绍了。…

FreeRTOS【14】软件定时器使用

1.开发背景 基于以上的章节&#xff0c;这个篇章主题是软件定时器使用&#xff0c;能使用 FreeRTOS 的基本都是从裸机 MCU 过来的&#xff0c;基本都知道 MCU 最基本的功能之一就是定时器&#xff0c;确切的说是硬件定时器&#xff0c;外围电路已经构建好的&#xff0c;精度很高…

bug 定位tag

mega: 解压所有log 命令 extract_and_rename . 播放 tag&#xff1a;MediaServiceConnection、BluetoothMediaBrowserService、PlaybackManager、MediaPlayEventListener message: AudioFocus、onPlaybackStateChanged:PlaybackState {state 网易云播放sdk问题&#xf…

【实战JVM】-实战篇-05-内存泄漏及分析

【实战JVM】-实战篇-05-内存泄漏及分析 1 内存溢出和内存泄漏1.1 常见场景1.2 解决内存溢出的方法1.2.1 发现问题1.2.1.1 top1.2.1.2 ViusalVM1.2.1.3 arthas1.2.1.4 PrometheusGrafana 1.2.2 堆内存状况对比1.2.3 内存泄漏原因-代码中1.2.3.1 equals()-hashCode()1.2.3.2 内部…

小程序-富文本编辑框的注意事项

富文本编辑框官网位置 表单组件 / editor (qq.com)https://developers.weixin.qq.com/miniprogram/dev/component/editor.html &#xff08;一&#xff09;富文本编辑框的作用 1.适用于一些表单的提交 2.这些表单内容需要自定义图片大小&#xff0c;编辑文字样式 主要用到的是…

MySQL分页:ROW_NUMBER() vs LIMIT

在 MySQL 中&#xff0c;实现数据分页的方法主要有两种&#xff1a;使用 ROW_NUMBER() 窗口函数和使用 LIMIT 子句。本文将探讨这两种方法的优劣&#xff0c;帮助您选择最适合您的场景。 1. ROW_NUMBER() 分页 ROW_NUMBER() 是 MySQL 8.0 及以上版本支持的窗口函数&#xff0…

【C++】10.list

list这个迭代器是双向迭代器&#xff0c;与vector的迭代器具有很大的区别&#xff0c;主要在于双向迭代器不支持&#xff0b;- 操作 正由于list的双向迭代器&#xff0c;因此<algorithm>中的sort()函数无法使用&#xff0c;list单独实现了一个sort()函数&#xff0c;但效…