【Java技术探索】带你攻克String类创建的难点分析
2021/6/9 14:21:50
本文主要是介绍【Java技术探索】带你攻克String类创建的难点分析,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
### 字符串常量池引入 > **String是一个引用类型,这意味着String类型的实例化与其它对象一样,相较于基本数据类型,时间和空间的消耗都是较大的,但是由于String的使用频率非常高,JVM为了提高性能和减少内存的开销,在实例化字符串的时候进行了一些优化,引入了字符串常量池。**。 ### 字符串创建过程 - **每当我们创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引用**。 - **如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。由于String字符串的不可变性我们可以十分肯定常量池中一定不存在两个相同的字符串** - **.class文件中的常量池将包含String字面量,在jvm进行类装载过程中,class文件中的常量池将被载入内存,此时便形成了所谓的字符串常量池。** ### 整体来说String对象的初始化分为两种 #### 初始化方式将会影响对象内存分配的方式, ##### 字面量初始化的形式创建字符串 ```java public class ImmutableStrings{ public static void main(String[] args) { String one = "someString"; // 1 String two = "someString"; // 2 System.out.println(one.equals(two)); // String 对象是否相同内容 System.out.println(one == two); // String 对象是否相同的引用 } } // Output true true ```` > 执行完上面的第一句代码之后,会在堆上创建一个String 对象,并把String 对象的引用存放到字符串常量池中,并把引用返回给 one,那当第二句代码执行时,字符串常量池已经有对应内容的引用了,直接返回对象引用给 two。one.equals(two) / one == two 都为true。 图形化如下所示: ![](https://oscimg.oschina.net/oscnet/up-9bf6f6af618c5dccd32cc06b1b903f2f89c.png) ##### 字符串拼接的初始化场景 ```java String s = "a"+"a"; String s2 = "aa"; System.out.println(s == s2); // true ``` 应该思考为什么会输出true,通过反编译可知jvm直接将上面的"a"+"a"在编译阶段直接变成了"aa"。 ![](https://oscimg.oschina.net/oscnet/up-0fee0c55d2b5c6d4855513a61a19dfa9f5e.png) ```java String s = "a"; String s1 = s + "a"; String s2 = "aa"; System.out.println(s1 == s2); // false ``` 上面这一段输出false,同样通过反编译 ![](https://oscimg.oschina.net/oscnet/up-4d21f5dd35ea58ccf0b238a42a5aabe1e26.png) 可以看出汇编指令明显比上面的长了许多,然后我们逐个分析s1的产生过程 1. 首先jvm会先生成一个StringBuilder对象 ![](https://oscimg.oschina.net/oscnet/up-a315704a105aaa32d30af0247a607eb6514.png) 2. 然后会添加s和"a",这里我们可以看出第一次添加的时候需要通过ldc出栈解析了字符串s的值,然后添加到StringBuilder对象中。 ![](https://oscimg.oschina.net/oscnet/up-6cda9e2d04655caa2545b87a677ebf143e6.png) 3. 最后调用StringBuilder对象的toString方法返回一个新的字符串对象。 ![](https://oscimg.oschina.net/oscnet/up-65a663008a2c257e673bea2ee5cadaf7d98.png) 4. StringBuilder的toString方法如下,所以上面s1==s2为false。 ![](https://oscimg.oschina.net/oscnet/up-b793553917c2ffba85e6d3ab70d6c9070a3.png) 通过上面的分析 - 我们可以知道当String s1 = "a" + "a"时在编译阶段由于可以直接确定s1的值,所以在编译阶段直接将s1的值赋值为aa - String s1 = s+ "a"在编译阶段中由于不知道s的内容(在编译阶段jvm不会知道一个对象的内容),所以需要运行期间来解析s并且通过StringBuilder进行优化来将它们相加。 > 所以我们在平时写代码的时候对于字符串拼接用StringBuilder来拼接,因为String类型相加底层用的StringBuilder,而每一次String相加都会生成一个对象,使用StringBuilder可以节约内存,避免内存溢出 ##### new创建字符串 > 众所周知String s = new String("a")将会在生成一个String对象,字符串a会不会加入到常量池中呢?我们对String s = new String("a")也进行反编译如下: ![](https://oscimg.oschina.net/oscnet/up-a087776c95ec93794d453d0338a706b001c.png) - **通过对上面进行反编译可以看到使用new创建对象的时候执行了ldc这个指令,ldc指令的意思是操作字符串常量池,如果有直接拉取下来,如果没有就创建一个对象在常量池中**。 - **通过反编译我们可以看出使用new String()创建对象的时候我们访问了字符串常量池的,那么是不是创建s对象的时候在常量池也创建了一个"a"呢**? 可以理解为 ```java String variable = "a"; // variable为匿名变量 String s = new String(variable); ``` 也就是说在第二种初始化中是包含了第一种初始化的,首先进行的是以字面量的形式创建匿名变量,具体流程与第一种方式初始化一致,然后new操作会在堆上创建s指向的String对象,也就是说第二种方式初始化实际上会创建两个String对象,一个存放在字符串常量池,一个存放在堆中; ##### 实际案例分析 ```java public class ImmutableStrings { public static void main(String[] args) { String one = "someString"; String two = new String("someString"); System.out.println(one.equals(two)); System.out.println(one == two); } } // Output true false ``` ![](https://oscimg.oschina.net/oscnet/up-f48c4c8c49bd8254c087cd73c68b9b3cf5e.png) 带着这个疑问我们看看String 的构造函数 ![](https://oscimg.oschina.net/oscnet/up-d9fa4e9398e3a611731a993f4581e723640.png) - **这个构造函数只是将"a"的value和hash赋值给了新创建的对象,而value是char[]类型的数组,hash也是int类型,这两个都不可能对字符串常量池访问,所以真正的原因只可能是传入的"a"是从字符串常量池中获取的,所以我们在new String()的时候有可能会生成两个对象。** - **所以对于new String("a")可能会生成两个对象,一个是字符串类型对象存放在堆中,另外一个就是字符串常量池对象,当然如果a 以前在字符串常量池中存在那么将不会创建字符串常量池对象。** > **注意:new String()本身不会在字符串常量池中创建相应的对象,new String("a")会生成两个对象的原因是因为"a"在加载new String("a");这行代码所存在的类的时候将其放入字符串常量池中的。比如"int"就是java在Integer类的初始化阶段时候在解析 public static final Class这篇关于【Java技术探索】带你攻克String类创建的难点分析的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23JAVA语音识别项目入门教程
- 2024-11-23Java云原生学习:从入门到实践
- 2024-11-22Java创业学习:初学者的全面指南
- 2024-11-22JAVA创业学习:零基础入门到实战应用教程
- 2024-11-22Java创业学习:从零开始的Java编程入门教程
- 2024-11-22Java对接阿里云智能语音服务学习教程
- 2024-11-22JAVA对接阿里云智能语音服务学习教程
- 2024-11-22Java对接阿里云智能语音服务学习教程
- 2024-11-22Java副业学习:零基础入门到实战项目
- 2024-11-22Java副业学习:零基础入门指南