Ignite

String s1 = new String("abc")和String s2 = "abc"的区别

2017-10-15

今天在看JVM的时候突然想到这样一个问题,即
1
2
3
4
String s1 = new String("abc");
String s2 = "abc";

System.out.println(s1 == s2);//答案是false

问题有两个:

String s2 = “abc”时发生了什么?
String s1 = new String(“abc”)时又做了什么?
第二个问题是比较好回答的,根据官方文档的解释:

当我们在jdk1.6中讨论时,常量池放在方法区中。(jdk1.7中常量池放在堆内存中,jdk1.8放在元空间里面,和堆相对独立,所以导致string的intern方法因为以上变化在不同版本会有不同表现。)

new String(“abc”);
Initializes a newly created String object so that it represents the same sequence of characters as the argument; in other words, the newly created string is a copy of the argument string. Unless an explicit copy of original is needed, use of this constructor is unnecessary since Strings are immutable.

简单解释一下:

初始化一个新创建的String对象,换句话说,新创建的字符串是参数字符串的一个副本。除非确实需要一份副本,否则这种方法是不必要的,因为String是不可变的

这句话实际上透露出两个意思,

在编译器编译的时候,当编译器注意到参数为字符串常量时,即将字符串作为常量放在class文件中的常量区,并在类加载时放入运行时常量池中。
在new操作符被调用时,在java堆中创建一个新的对象,然后对象的内容为常量池里面对应字符串的一个拷贝。
而在String s2 = “abc”被编译的时候,先检查class文件中是否包含该字符串常量,如果包含,直接返回常量池中的对象。

因此,在调用new操作时,对象始终存在于堆中,而直接字符串赋值时对象实际上是存在于常量池中的,
所以比较结果肯定是false

String s = new String(“hello”);

Generally speaking,
  • jdk1.6中: 首先"hello"字符串对象保存在 方法区的字符串常量池中, 在虚拟机栈中开辟空间 用来存放String 类型的变量s,在堆中开辟空间
    存放 s 引用的对象,然后将常量池中的“hello” 拷贝一个副本给堆中的String。
  • jdk1.7中:首先"hello"字符串对象保存在堆内存的字符串常量池中
    • 1】在栈中开辟空间存放 s
    • 2】在堆中开辟空间存放新建的String 对象"hello"
    • 3】引用s指向堆中新建的String对象“hello”。

参考文章1、(https://blog.csdn.net/weixin_35663229/article/details/52796157?locationNum=15)
参考文章2、(https://blog.csdn.net/u010644448/article/details/51980370)

Tags: Mysql
使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章