要为您已经得到的答案添加更多信息:
Java 有两种类型的存储。一个是堆栈,其中包括变量名称及其值。一个是堆,它只是一个巨大的自由浮动对象的集合。
现在,如果您正在使用原始类型(如 或) int
,则分配一个变量,如
将变量推送到堆栈上 - 名称是,值是。boolean
char
int myInt = 1;
myInt
1
但是,如果您有一个对象(如字符串),则分配一个变量会做更多的事情。现在在堆的某处
String myString = "Hey!";
创建一个对象(的实例)。String
它在那里没有名字,只有内存中可以找到它的某个地址。
除此之外,它将一个变量压入堆栈。名称是myString
- 值是堆上对象的地址。
那么为什么这与比较变量有关呢?因为==
比较变量的值。在堆栈上,就是这样。所以如果你比较原始类型,一切都会按预期工作。但是如果你在比较对象,==
仍然只比较变量的值——在这种情况下,就是对象的地址。如果地址相同,则返回 true。这确实意味着,两个变量都指向同一个对象。如果地址不同,则==
返回 false。,无需查看对象真正所在的堆。
一个例子:
String a = new String("Hey!");
String b = a;
if (a == b) System.out.println("true");
else System.out.println("false");
将回显“true” - 因为两个变量都包含相同的对象。
String a = new String("Hey!");
String b = new String("Hey!");
if (a == b) System.out.println("true");
else System.out.println("false");
将回显“false” - 因为您现在在堆上有两个对象,并且a
指向一个,而b
指向另一个。因此,虽然两个对象的内容可能相同,但堆栈的内容a
和b
堆栈上的内容是不同的。
因此,要比较任何对象,.equals()
如果要比较内容,请始终使用,而不是实例相等。
[附录]:使用字符串,这更加复杂。正如你已经发现的那样,
String a = "Hey!"; // mention the difference to the example above:
String b = "Hey!"; // I did NOT use the `String()` cosntructor here!
if (a == b) System.out.println("true");
else System.out.println("false");
实际上会给你“真实”。为什么会这样?有人可能会认为我们仍然创建了两个对象。但实际上,我们不是。
String
是不可变的。这意味着,一旦创建了字符串,就无法修改它。曾经。不相信?看一看!
String myString = "test"; // we create one instance of String here
myString += " and more"; // we create another instance of String (" and more")
// and append that. Did we modify the instance stored in
// myString now? NO! We created a third instance that
// contains "test and more".
因此,无需创建String
具有相同内容的其他实例 - 这会提高性能,因为字符串被广泛使用,大量使用,因此我们希望尽可能少地使用它们。为了归档它,JVM 维护了一个我们已经创建的字符串对象列表。每次我们写下一个字符串字面量(类似于"Hey!"
)时,它都会查看该列表并检查我们是否已经创建了一个具有该值的实例。如果是这样,它会返回一个指向该完全相同实例的指针,而不是创建一个新实例。
这就是,为什么"Hey!" == "Hey!"
会返回true。