【剧前爆米花--爪哇岛寻宝】String类型构造,修改的底层逻辑与StringBuilder和StringBuffer的关系

作者:困了电视剧

专栏:《JavaSE语法与底层详解》

文章分布:这是一篇关于String类型及其底层构造的文章,如有疏漏,欢迎大佬指正!

【剧前爆米花--爪哇岛寻宝】String类型构造,修改的底层逻辑与StringBuilder和StringBuffer的关系_第1张图片 

String对象的创建

字符串的用法比较多,所以String类提供的构造方式也比较多,这里展示三种常用的构造方式:

public static void main(String[] args) {
        String str1="aaa";
        //==============================
        String str2=new String("bbb");
        //==============================
        char[] array={'c','c','c'};
        String str3=new String(array);
    }

了解了如何构建一个字符串后,我们还需要了解String对象底层的构造逻辑,下面让我们打开看一下String类的源码:

【剧前爆米花--爪哇岛寻宝】String类型构造,修改的底层逻辑与StringBuilder和StringBuffer的关系_第2张图片

可以看到,String是引用类型,内部并不存储字符串本身,字符串实际保存在char类型的数组中,这一点跟C语言构造字符串很像,可以进行参考。

字符串常量池

在工作中,String类是我们使用频率非常高的一种对象类型。JVM为了提升性能和减少内存开销,避免字符串的重复创建,其维护了一块特殊的内存空间,这就是字符串常量池。字符串常量池由String类私有的维护

https://blog.csdn.net/m0_62815572/article/details/127887112在这篇文章中,我简要介绍了java对内存的分区。在jdk7之后字符串常量池被分进了堆区。

当我们创立一个String对象时,比如上述栗子中的str1,由于我之前并没有创建过内容为"aaa"的String对象,所以我的这个"aaa"就会被放入常量池中,当我下次在需要"aaa"这一字符串的时候,java就会从常量池中直接取出节约时间。

public static void main(String[] args) {
        String str1="aaa";
        String str2=new String("aaa");
    }

就比如现在有这样一段代码,他们在内存中的创建方式具体为:

【剧前爆米花--爪哇岛寻宝】String类型构造,修改的底层逻辑与StringBuilder和StringBuffer的关系_第3张图片

str1直接指向在常量池中的对象 ,str2由于是通过new String对象的方式创建的,所以会单独地在堆区中在开辟一块String的空间,然后这个对象的value数组再指向常量池的"aaa"。

String对象的修改 

由String类的源码我们可以看到value数组是由final修饰的,并且当一个String对象被创建后,其字符串的值会被放在常量池中,value数组也会指向字符串的地址,那此时如果我想对字符串进行修改怎么办,让我们反编译一下,看看java是怎样做的:

【剧前爆米花--爪哇岛寻宝】String类型构造,修改的底层逻辑与StringBuilder和StringBuffer的关系_第4张图片

现在有这样一段简单的代码,它的运行结果也在意料之中 

【剧前爆米花--爪哇岛寻宝】String类型构造,修改的底层逻辑与StringBuilder和StringBuffer的关系_第5张图片

这就是这段代码在运行过程中的背后逻辑了,我们可以发现一个神奇的点,java程序为了完成这一操作引用了StringBuilder类,根据注释我们可以理解他大体的逻辑就是:先创建一个StringBuilder对象,然后这个对象通过append方法实现字符串的拼接,最后运用toString方法,将拼接后的字符串返回成一个String对象,完成功能。那这个StringBuilder类又是什么呢?

StringBuilder类

我们打开StringBuilder的源码一探究竟

【剧前爆米花--爪哇岛寻宝】String类型构造,修改的底层逻辑与StringBuilder和StringBuffer的关系_第6张图片

【剧前爆米花--爪哇岛寻宝】String类型构造,修改的底层逻辑与StringBuilder和StringBuffer的关系_第7张图片

由这我们可以看出StringBuilder和String的一个很大的区别就是,StringBuilder的value数组并没有被final所修饰,也就是他不是一个常量,可以更改指向,再看一下append方法

 【剧前爆米花--爪哇岛寻宝】String类型构造,修改的底层逻辑与StringBuilder和StringBuffer的关系_第8张图片

【剧前爆米花--爪哇岛寻宝】String类型构造,修改的底层逻辑与StringBuilder和StringBuffer的关系_第9张图片

可以看出在append方法中,append完成字符串的拼接后不会return一个新的对象而是return this,所以如果我们需要大量的拼接操作的话,用StringBuilder类会节约很多资源,提高效率。 

举个栗子

String str = new String("ab"); // 会创建多少个对象
String str = new String("a") + new String("b"); // 会创建多少个对象

第一个是创建两个对象。

第二个会创建一个StringBuilder对象,这个对象完成拼接后由于接受的是String对象所以还会进行一次toString创建一个String对象,所以一共6个对象。

StringBuilder类与StringBuffer类的区别

 【剧前爆米花--爪哇岛寻宝】String类型构造,修改的底层逻辑与StringBuilder和StringBuffer的关系_第10张图片

这两个类的父类相同,在重写的方法中 

【剧前爆米花--爪哇岛寻宝】String类型构造,修改的底层逻辑与StringBuilder和StringBuffer的关系_第11张图片

StringBuffer多了一份线程上相关知识的运用,在本质上没有太大的区别。 

 

你可能感兴趣的:(JavaSE语法与底层详解,java,开发语言,jvm)