JAVA中String的底层解析

Java中字符串String类,String类型的底层原理,什么是StringBuffer,StringBuffer类的原理 String、StringBuffer 阅读详情

JAVA中String 是Final类不能被继承。JAVA 对String的处理和一般Class有所不同。
这文章主要是解释一下String的存储模式和java的字符串常量池的机制,和几个涉及底层的引用问题解析。

首先提出几个问题:
1.String的内容为什么是不可更改的?
2.JAVA中“adc”这种创建的字符串的创建过程是怎样的?
3.String(String string)的构造方法是如何工作的?
4.一个线程中内容为“adc”的String对象,存储的char[]是否是同一个,char[]数组是否一定在字符串常量池中?
5思考java中String 不可更改的好处在哪?
6 intern方法和字符串常量池的关系?
7string的+编译器是如何处理的?

1.String的内容为什么是不可更改的?
我们通过源代码可以看到存储string内容的char[]是这么定义的:

private final char value[];

可能有人会有疑问既然是final引用却没有附初始值。
答案是final变量是可以在构造方法中进行赋值的。
所以value的所有赋值都在String的几个构造方法中。
这样从代码逻辑上控制了String不可变。

2.JAVA中“adc”这种创建的字符串的创建过程是怎样的?

这个问题比较简单,就是”adc“会被放到字符串常量池中,可以称为字面量,所有String s=“adb” 的字符串的引用都是指向字符串常量池中的。

3.String(String string)的构造方法是如何工作的?

 public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }

这说明从用String去new String构造新的对象是,确实会产生新的对象,而且新的value和hash值都和原String对象一致。
当然String还是有其他构造方法,都会去new char[]

4一个线程中内容为“adc”的String对象,存储的char[]是否是同一个,char[]数组是否一定在字符串常量池中?
答案其实可以根据3推导出。
由String产生的String里面的char[]是同一个,其他方式产生的都是新的。“”包裹产生的字符串会在常量池中,其他的都是正常的存在堆中。所以堆中可以有n份“adb”的串,常量池中的“adc”永远只有一个,可以被多个引用所指向。后续将会用代码解释上述所有现象。

public static void main(String[] args)
			throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
		// TODO Auto-generated method stub

		String string = "abc";
		String string2 = "abc";
	    String string3 = new String(string);
	    char[] charString={'a','b','c'};
		String string4 = new String(charString);
		String string5 = new String(string4);
		
		charString[2]='e';
	
		Class sClass = String.class;
		Field privateStringField = sClass.getDeclaredField("value");
		privateStringField.setAccessible(true);
		char[] chars = (char[]) privateStringField.get(string);
		char[] chars2 = (char[]) privateStringField.get(string2);
		char[] chars3 = (char[]) privateStringField.get(string3);
		char[] chars4 = (char[]) privateStringField.get(string4);
		char[] chars5 = (char[]) privateStringField.get(string5); 
		
		System.out.println("++" + chars + "       " + Arrays.toString(chars));
		System.out.println("++" + chars2 + "       " + Arrays.toString(chars2));
		System.out.println("++" + chars3 + "       " + Arrays.toString(chars3));
		System.out.println("++" + chars4 + "        " + Arrays.toString(chars4));
		System.out.println("++" + chars5 + "       " + Arrays.toString(chars5));
		System.out.println("++" + charString + "       " + Arrays.toString(charString));
		System.out.println(string==string2);
		System.out.println(string3==string);
		System.out.println(string4==string);
		System.out.println(string5==string4);
		
		

	}

控制台输出:

++[C@4e25154f       [a, b, c]
++[C@4e25154f       [a, b, c]
++[C@4e25154f       [a, b, c]
++[C@70dea4e        [a, b, c]
++[C@70dea4e        [a, b, c]
++[C@5c647e05      [a, b, e]
true
false
false
false

我们用反射可以拿到char[] 的引用,并打印出char[] 指向的内存地址。
可见前三个String都是指向同一个地址的(字符串常量池),后三个String都是指向堆中的地址。

5思考java中String 不可更改的好处在哪?
1.如果可变复用将变得不稳定。复用可以节约内存
2.hashcode被缓存,没必要重复结算
3.线程安全(网上的说法,我并不完全赞同,能保证值得安全,并不能保证引用的安全总是)
4.如果定义为final 也就是String的引用和内容都会稳定不可变(当然不包括使用反射的情况)

6intern方法的作用?
intern的作用是 将string放入常量池,并返回该引用,如果已经在常量池中直接返回引用。
在JDK1.6之后 intern方法是将不存在字符串常量池的String去记录到常量池里(存的是引用)实例还是在堆上
在JDK1.6之前intern方法是把String复制到字符串常量池里是新对象了(据说是在永久代中)目前可以确定String实例肯定不是一个了,里面的char[]是否复用,这个还不确定,手里没有JDK16的环境,可以用我上面的反射方法来进行验证。

7string的+编译器是如何处理的?
两种情况:
如果只是“” +“”+“”+… 不涉及变量的,javac会直接合并所有的"" “” ,形成utf8 结构体,保存下来,结构体中有个2byte的length字段记录字面量(”“这种东西官方称为字面量)在类运行中会把结构体的东西加载到内存的字符串常量池中(具体加载细节后续再聊)
第二种情况:

        String j1="a";
	    String j2="b";
	    String j12="ab";
	    String j3="a"+j12;
	    System.out.println(j3 == j12); (输出是false)

遇到这种情况javac并不会合并”“ ”“,尽管j12也是字面量的变量。我们可以通过javap -c查看字节码:

Code:
       0: ldc           #2                  // String a
       2: astore_2
       3: ldc           #3                  // String b
       5: astore_3
       6: new           #4                  // class java/lang/StringBuilder
       9: dup
      10: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
      13: ldc           #2                  // String a
      15: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      18: aload_3
      19: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      25: astore        4

很清楚的看到,这里会new StringBuilder 调用append方法,最后toString。StringBulider的toString方法我们可以看一下,是根据当前的char[]去 newString的,所以必然不是用一个对象,所以输出的结果是false。

未完待续…

Java教程之String类的底层原理和版本演变 intern() 方法将这个字符串对象尝试放入常量池中,并返回地址。jdk1 . 6 中:如果池中有,则不会放入,返回已有的池中的对象的地址。如果池中没有,则把此对象重新创建一份,放入池中,并返回池中新的对象地址。jdk1 . 7 起:如果池中有,则不会放入,返回已有的池中的对象的地址。如果池中没有,则把此对象的引用地址复制一份,放入池中,并返回池中的引用地址。 阅读详情

相关推荐

String/StringBuilder/ToString()底层代码解析( JAVA / C# )

本章笔记直接记录的string、StringBuilder内存存储原理,并没有大幅度、重点的去介绍堆、栈、常量池的相关底层实现原理。所以,为了帮助大家更好的去理解,可以在阅读本文章前去了解堆、栈、常量池之间的基础关系,对以下的阅读有很大的帮助。 ToString底层代码解析(C#/JAVA)——分别浅谈 C# / JAVA 底层实现代码与区别...

weixin_46484674的博客 7464

String字符串相关类底层原理

刚才在第一点我们也说了,String字符串一经创建,值就不可变,当我们在程序编程时,如果对字符串进行拼接,实际上会产生新的字符串,这样不仅会降低程序的执行效率,还会创建出多余无用的字符串垃圾,非常不好。那么有没有更好的解决方案来应对字符串可变化的这一需求呢?当然是有的,它就是我们要说的 StringBuilder。StringBuilder我们可以把它看作是一个容器,创建之后内容是可变的,它可以很大的提高字符串的操作效率。StringBuilder有两个常用的构造方法,如下图所示。

m0_70325779的博客 646

光电振荡器(OEO):从原理到应用,解锁高频微波信号新纪元

本文深入解析了光电振荡器(OEO)的核心原理与前沿应用。OEO通过巧妙的光-电-光转换机制,利用光学谐振腔产生高频、高纯度、低相位噪声的微波信号,有效突破了传统电子电路的频率瓶颈。文章详细拆解了其工作流程,并探讨了在雷达系统、高速光通信及精密测量等领域的硬核应用价值。

weixin_29231027的博客 367

String底层解析

String解析

空杯 2013

原形网络(Prototypical Networks)基于PyTorch的实现

我在Jay2coomzz的基础上修改了数据处理方式和evaluation_model()方法,作为初学者若有不当之处恳请大家批评指正,原文链接如下: https://blog.youkuaiyun.com/weixin_38471579/article/details/102631018 数据集和源码链接将放到评论区 文章目录1 数据集一个简单的数据集介绍数据集处理2 搭建网络CNNProtonets 1 数据集 一个简单的数据集介绍 Omniglot数据集一共包含1623 类手写体,每一类中包含20 个样本。其中.

weixin_43872532的博客 6637

【NAS系统】DSM7.2部署SVN服务

早期的群晖版本可以在套件中心找到SVN Server直接安装,然后配置仓库和用户。但‌2提到DSM7.0之后套件中心没有SVN了,得用Docker。

qq_38350004的博客 4852

java string底层实现_Java基础底层-String类基础

一、概念String是所有语言中最常用的一个类;是不可变的,是最终类(final),最终类不能被继承。核心特点 对String对象的任何改变都不影响到原对象,相关的任何操作都会生成新的对象二、声明方式 2.1 指令码分析2.1.1 直接赋值在编译期间,会将等号右边的abc常量放入常量池(ldc),在程序运行时,会将str1变量压栈,栈中的str1变量直接指向字符串常量池的abc项,没有经过堆内存 ...

weixin_33879932的博客 1921

Rockit VDEC解码实战:从零构建高效视频处理流水线

本文详细介绍了Rockit VDEC硬件解码模块在RK3568/RK3588平台的应用实践,涵盖开发环境配置、MPI接口使用、码流发送模式选择、内存管理优化及多路解码系统构建。通过实战案例展示如何利用VDEC实现高效视频处理流水线,显著降低CPU占用率,提升嵌入式多媒体开发效率。

ol789012的博客 305

不懂String?Java中String底层原理详细解析,以及String常见的错误和解决方式,跟着我带你get到String精髓

Java中的String是一个非常常用的类,用于表示不可变的字符序列。下面对String类的底层原理进行详细说明,并附带代码和经常遇到的错误解析。String类使用一个char类型的数组来保存字符串中的每个字符,同时还有一个int类型的变量count来表示字符串的长度。由于String类是不可变的,因此一旦创建了一个String对象,就不能修改其中的字符序列。当使用String。

GuoFuMengXiang的博客 2716

走向审计4.0:内部审计数字化转型的路径与方法

企业的内部审计人员可以以数字化为手段,建立内部审计新生态,在数字化过程中引进战略审计、服务审计、开放审计、敏捷审计、数字审计、智慧审计等理念、方法和工具,完成数智生态审计转型。内部审计的审计对象远比国家审计和公众审计丰富和多元化,理论上企业经营管理和日常操作的各个方面都可以成为内部审计的对象,此外还可以开展独立咨询活动。由于内部审计的数字化或数字化的内部审计是实现审计数字化转型的必要条件,是实现“数字引领、数据强审”目标的核心手段,因此企业内部审计部门势必要投入足够的资金和人才来打造一支数字化审计新队伍。

一键难忘的博客 6737

DICOM标准:DICOM医学影像中的覆盖层(Overlay)概念详解

DICOM标准:深入详解DICOM医学影像中的覆盖层(Overlay)

编程技术探索者,分享C/C++、C#、Java、数据库等开发经验,聚焦实战技巧与AI兴趣,助力编程爱好者成长。 1564

java tostring底层_String底层解析

目录关于StringString类型的底层代码是Java所有底层代码中相对来说比较简单、好理解。同时,String底层的源码又是面试官经典的“面试第一题”。“良好的开端就是成功的一半”,因此这个问题回答的好坏会很大程度影响你接下来的面试。我会在这篇博客中梳理几个面试中频率较高的知识点。String内部结构String内部存储结构为char数组,有两个私有变量,一个是char[],哈希值。具体结构:...

weixin_39545329的博客 442

【考试大纲】中级多媒体应用设计师考试大纲

中级多媒体应用设计师考试大纲

邓邓子的博客 382

Java String 类型赋值底层逻辑解析:两种方式与避坑指南

本文深入解析Java中String类型的两种赋值方式(直接赋值与new关键字)的底层原理和差异。直接赋值会利用字符串常量池实现对象复用,提升效率;而new关键字强制在堆内存创建新对象。文章通过代码示例和内存模型对比二者的关键区别,并提供了实际开发中的避坑指南,包括正确比较字符串、优化字符串拼接、合理使用intern()方法等最佳实践,帮助开发者正确选择赋值方式以避免内存浪费和潜在错误。

jingpide9527的博客 1167

基于FPGA的BP神经网络Verilog设计与Matlab仿真

BP(Backpropagation)神经网络是一种常见且广泛应用的神经网络类型,通过反向传播算法实现训练和学习。本文将介绍如何使用Verilog语言在FPGA上设计一个简易的BP神经网络,并使用Matlab进行仿真验证。BP神经网络由输入层、隐藏层和输出层组成。在上述Verilog代码中,我们定义了BP神经网络的输入层、隐藏层和输出层的神经元数量,并声明了相应的信号和参数。在上述Verilog代码中,我们定义了BP神经网络的输入层、隐藏层和输出层的神经元数量,并声明了相应的信号和参数。

2301_79326254的博客 560

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

java string底层实现_JAVA中String的底层解析常见面试问题

JAVA中String 是Final类不能被继承。JAVA 对String的处理和一般Class有所不同。 这文章主要是解释一下String的存储模式和java的字符串常量池的机制,和几个涉及底层的引用问题解析。首先提出几个问题:1.String的内容为什么是不可更改的?2.JAVA中“adc”这种创建的字符串的创建过程是怎样的?3.String(String string)的构造方法是如何工作的...

weixin_29476767的博客 372

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

深度解析String不可变性:从Java底层到设计哲学

Java中String的不可变性是其核心设计之一。String类通过final修饰、私有final字段和无修改方法实现不可变特性。这种设计确保了线程安全,优化了哈希缓存和字符串常量池机制,提高了安全性。虽然反射可以突破限制,但会带来严重风险。从Java 9开始,String内部改用byte[]存储以节省空间。在实际开发中,应合理使用StringBuilder进行高效字符串操作,对敏感信息使用char[]而非String。理解String不可变性有助于编写更安全高效的Java代码。

m0_66884848的博客 1081

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Java高级面试10大高频送命题深度解析:从String到ThreadLocal的底层原理

在Java开发领域,理解核心机制底层原理是区分普通开发者与高级工程师的关键。从内存模型到并发编程,Java语言规范定义了对象创建、方法调用和线程交互的基本规则。这些原理决定了程序的性能、稳定性和可维护性,是构建高并发、高可用系统的技术基石。例如,String常量池机制通过复用不可变对象优化内存使用,而volatile关键字则通过内存屏障保证多线程间的可见性。在实际应用场景中,HashMap的快速失败机制防止了迭代过程中的数据不一致,ThreadLocal的弱引用设计则需要配合remove()调用来避免线程池

weixin_34062469的博客 353

java常用方法还有String、StringBuilder、StringBuffer底层解析

记录Java方法常用 String类常用的方法一: char charAt(int index) 返回字符串中index位置处的字符,index从0开始 int compareTo(String anotherString) 比较当前字符串与anotherString字符串的大小。当前字符串大,则返回正整数;当前字符串小,则返回一个小于0的整数;两者相等,则返回0 int compareToIgnoreCase(String anotherString) 比较两个字符串的大小,比较时,忽略大小写;返回结果和

HolleDream的博客 192

Java String 全解析:从底层存储到高效使用

也可以使用compareTo ⽅法,与equals不同的是,equals返回的是boolean类型,⽽compareTo返回的是int类型。在 Java 语言中,字符串的使用非常广泛、频率极高,因此 Java 专门提供了 String 类 来对字符串进行统一的创建、管理和操作。String类重写了⽗类Object中equals⽅法,Object中equals默认按照==⽐较,String重写equals⽅法。为此Java 专门为字符串开辟的一块内存区域,为字符串常量池,equals ⽅法:按照字典序⽐较。

2201_75758787的博客 398

Java String底层原理深度解析:常量池、intern与字符串拼接机制

String是Java中最基础又最易被误解的核心类,其不可变性、内存布局与JVM常量池紧密耦合。理解String需从对象创建机制切入:字面量直接入常量池,new String()则在堆中分配,二者地址不同导致==比较为false;intern()方法在JDK7+后将对象引用登记至堆内常量池,彻底改变语义;而字符串拼接的三种路径(+、StringBuilder、concat)对应不同字节码实现与性能特征。这些原理直接影响GC压力、序列化体积、缓存Key一致性及安全风险。本文围绕真实高频误区展开,涵盖常量池定位

weixin_30667649的博客 399

Java基础篇——Java String 深度解析:底层实现、不可变性、常量池与相关类全解读

java string详解

m0_59624833的博客 1656

Java 字符串数据结构深度解析:String、StringBuffer 与 StringBuilder 的底层实现与性能优化

和均继承自// 可变字符数组int count;// 当前有效字符数// 扩容策略:当前容量 * 2 + 2可变,支持原地修改初始容量为 16(无参构造)动态扩容机制,避免频繁内存分配| 特性 | String | StringBuffer | StringBuilder || 是否可变 | ❌ 不可变 | ✅ 可变 | ✅ 可变 || 线程安全 | ✅ 是 | ✅ 是 | ❌ 否 || 性能 | 最差 | 中等 | 最优 |

qq_54076831的博客 911

重新认识java中的String对象

java底层实现细节 JDK6 由char[], hash, offset, value组成。 JDK8 private final char value[];// 该值用于字符存储。 private int hash; // 缓存字符串的哈希码,默认为0。 少了offset和count两个变量,占用内存少,同时String.subString方法也不再共享char[],从而解决了可能导致的内存泄漏问题。 String对象的创建 JVM创建对象简介: ​ java中对象的创建都是在堆..

Lvlht的博客 628

Java源码解析

String源码解析

nice_meng的博客 724
上一篇: 补间动画和属性动画内存泄露分析
下一篇: RecycledViewPool的使用和堆内存分析
AndroidMsky
博客等级 码龄11年 270粉丝 45原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值