import java.util.*;
import java.lang.*;
import java.io.*;
class Test {
public static void main (String[] args) {
String a="hello"+"world"; //line 1
String b="hello";
String c="world";
String d=b+c;
String e="helloworld";
System.out.println(e==a);
System.out.println(a==d);
}
}
输出:
true
false
从这次讨论中How does the String class override the + operator?我明白了这一点,' a'并且' e'将引用相同的String文字对象。
请有人告诉
为什么 a 和 d 不是指同一个字符串文字对象?
在第1行中创建了多少个对象
答案 0 :(得分:15)
当结果不是编译时常量表达式(第15.28节)时,字符串连接运算符
+
(第15.18.1节)隐式创建一个新的String对象。
因为a的字面值是"helloworld"
而d的字面值是b
+ c
的参考对象,而不是上面的文字 JLS 4.3.3 即可。
字符串文字由用双引号括起来的零个或多个字符组成。
编译时常量表达式是表示基本类型值的表达式或不突然完成的字符串,仅使用以下内容组成:
- String类型的原始类型和文字的文字(§3.10.1,§3.10.2,§3.10.3,§3.10.4,§3.10.5)
如果您想System.out.println(a==d);
为真,请使用final
关键字,请参阅以下代码:
String a="hello"+"world"; //line 1
final String b="hello"; // now b is a literal
final String c="world";// now c is a literal
String d=b+c;
String e="helloworld";
System.out.println(e==a);
System.out.println(a==d);// now it will be true because both are literals.
回答评论:
第1行创建了多少个对象:答案是3
字符串a =“你好”+“世界”;
第一个文字对象
hello
第二个文字对象world
第三个文字对象"hello"+"world"
=="helloworld"
答案 1 :(得分:2)
==
符号检查对变量的引用是否相同。要检查是否有任何对象与其他对象相同,请使用Object.equals(Object o)方法,如下所示:
e.equals(a);
答案 2 :(得分:1)
==
运算符检查引用相等性,而不是对象相等性。在您的示例中,已创建了两个内容为String
的{{1}}个实例。变量"helloworld"
和a
引用相同的实例(请参见下文),而e
和a
则不是。可以使用d
方法检查字符串相等性,即equals()
为真。
a.equals(d)
和a
引用相同实例的原因是字符串常量被实现。每次遇到字符串常量(如e
)时,都会检查是否已经遇到这样的常量,如果有,则返回旧的"helloworld"
实例,而不是创建新的实例。虽然String
看起来不像String常量,但它被Java编译器优化为String常量,因此它被"hello" + "world"
实例化,这就是e
为真的原因。相反,a == e
未针对常量进行优化,这就是b + c
为假的原因(但a == d
为真)。
答案 3 :(得分:1)
1)这是因为 String 对象是不可变的。创建 String 对象并为其赋值后,它将永远具有无法更改的相同值。因此,当您使用它进行任何操作(例如加入)时,始终会创建一个新的 String 对象。
在堆中,它有一个特殊部分,用作 String 常量的池。如果编译器遇到 String 文字,它首先会查看内存的这一部分是否已存在相同的对象( String )。如果是,则为该现有对象( String )分配引用,而不是创建新对象。 (这就是为什么 String 是不可变的,所以没有人可以改变它。因为如果有几个引用指向这个 String ,其中一个会改变它的值,它会造成混乱。)
现在让我们看一下此代码段中的内容,并尝试立即找到两个问题的答案。
(1) String a="hello"+"world"; //line 1
(2) String b="hello"; // now b is a literal
(3) String c="world";
(4) String d=b+c;
(5) String e="helloworld";
(6) System.out.println(e==a);
(7) System.out.println(a==d);
(1)首先创建一个指向String类型的引用值 a 。然后在前面提到的堆(第一个String对象)中的这个特殊池中创建了文字“hello”。然后在池中创建了文字“世界”(第二个String对象)。然后,因为字符串是不可变的,所以在这个池中创建了另一个文字 - “helloworld”,它被分配给这个引用变量 a (第三个String对象 - 这是你的问题的答案Nr.2。 )。
(2)在(1)中创建的文字“hello”和“world”是在池中创建的,并没有分配给任何参考值,但它们仍存在于此池中。在此行中,创建了类型为String b 的引用变量,并将其分配给池中存在的此文本“hello”。
(3)与(2)相同
(4)创建String d 类型的引用值。虽然在这个特殊的堆部分(池)中已经有一个 String 文字,其值为“helloworld”,但是在堆中创建了一个新的String对象,其值为“helloworld”表示堆的非池部分。因此,您有两个类型为 String 的不同对象,其值为“helloworld”(一个在池中,另一个在堆的非池部分中)。如果现在与==运算符引用值 a 和 d 进行比较,则它们都指向不同的对象(但是具有相同的值,因此方法等于将返回true)。 / p>
(5)创建String类型的参考值 e 。在堆的池部分中已经存在一个字符串“helloworld”(我们在(1)中创建它并将其指向引用变量 a ),因此分配了引用变量 e 对这个对象。并指向与 a 相同的位置。因此,如果您比较参考 a == e ,您就会得到真实。方法等于
也是如此(6)和(7)在前面的几点中进行了解释
TLDR:
1)因为它不是同一个对象
2)3
答案 4 :(得分:0)
==
运算符检查两个对象是否引用内存中的相同位置。
a = "hello" + "world;"
评估为文字"helloworld"
,并给出了e="helloworld"
。它们指的是相同的内存位置。因此,表达式e==a
的计算结果为真。
表达式d=b+c
也评估为"helloworld"
,但此结果存储在其他位置。它不是指同一个对象。因此,表达式a==d
的计算结果为false。
使用a.equals(d)
将输出true,因为equals()
会检查2个对象的内容。