返回

和java.lang.String类关联探讨new运算符背后的秘密

前端

当我们看到一道这样的面试题时:

String s1 = new String("Tom");
String s2 = "Tom";
System.out.println(s1 == s2);

第一反应可能觉得s1和s2会相等,但输出结果却是false,这时可能就要去思考下是不是自己忽略掉了new运算符的作用了。

抱着这种疑问,我们去看看文档是怎么解释的:

使用new运算符创建字符串对象时,编译器执行以下步骤:

  1. 在常量池(如果有必要)中查找与字符串文字匹配的字符串字面值。
  2. 如果找到匹配的字符串字面值,则返回对此字符串字面值的引用。
  3. 否则,创建一个新的字符串对象,并将字符串文字复制到该对象中。然后将对该字符串对象的引用返回。

这就清楚了,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运算符来创建字符串对象,因为这不仅会降低代码的可读性和可维护性,还会增加内存的消耗。