和java.lang.String类关联探讨new运算符背后的秘密
2023-11-12 18:10:25
当我们看到一道这样的面试题时:
String s1 = new String("Tom");
String s2 = "Tom";
System.out.println(s1 == s2);
第一反应可能觉得s1和s2会相等,但输出结果却是false,这时可能就要去思考下是不是自己忽略掉了new运算符的作用了。
抱着这种疑问,我们去看看文档是怎么解释的:
使用
new
运算符创建字符串对象时,编译器执行以下步骤:
- 在常量池(如果有必要)中查找与字符串文字匹配的字符串字面值。
- 如果找到匹配的字符串字面值,则返回对此字符串字面值的引用。
- 否则,创建一个新的字符串对象,并将字符串文字复制到该对象中。然后将对该字符串对象的引用返回。
这就清楚了,java的编译器在遇到new运算符创建字符串时,会首先在常量池中查找是否已经存在相同的字符串,如果有,则直接返回对该字符串的引用,否则才创建新的字符串对象。
那么问题来了,为什么文档强调了这个细节呢?难道说有时候new运算符是多余的吗?
答案是肯定的,而且这一点已经从另一个角度说明了java在优化上的极致用心和强大之处。
正常情况下,我们创建一个字符串变量并对其赋值,比如:
String name = "Tom";
此时,编译器在编译时会对name直接赋值为"Tom",而无需像new运算符那样先在常量池中查找。
这看上去似乎和new运算符的效果是一样的,但两者之间却有着本质的区别。
首先,new运算符创建的字符串对象存储在堆内存中,而直接赋值的方式创建的字符串对象则存储在栈内存中。
其次,new运算符创建的字符串对象是可变的,而直接赋值的方式创建的字符串对象是不可变的。
最后,new运算符创建的字符串对象可以被多个变量引用,而直接赋值的方式创建的字符串对象只能被一个变量引用。
所以,在开发中,我们应该尽可能的避免使用new运算符来创建字符串对象,因为这不仅会降低代码的可读性和可维护性,还会增加内存的消耗。
当然,有时候我们也必须使用new运算符来创建字符串对象,比如当我们需要创建一个可变的字符串对象时,或者当我们需要创建一个可以被多个变量引用的字符串对象时。
例如,如果我们要创建一个可变的字符串对象,我们可以使用以下代码:
String name = new String("Tom");
如果我们要创建一个可以被多个变量引用的字符串对象,我们可以使用以下代码:
String name = new String("Tom");
String name2 = name;
总之,new运算符在创建字符串对象时起着至关重要的作用,它可以帮助我们创建可变的字符串对象,也可以帮助我们创建可以被多个变量引用的字符串对象。
但是,在开发中,我们应该尽可能的避免使用new运算符来创建字符串对象,因为这不仅会降低代码的可读性和可维护性,还会增加内存的消耗。