关于java中==运算符的问题
public class Demo {
public static void main(String[] args) {
String s1 = "Hello";
String s2 = "Hello";
System.out.println("s1 == s2 " + (s1 == s2));
String s5 = "Hel" + "lo";
String s6 = "He" + "llo";
System.out.println("s5 == s6 " + (s5 == s6));
String s7 = "He";
String s8 = "Hello";
s7 = s7.concat("llo");
System.out.println("s7 == s8 " + (s7 == s8));
String s10 = "He";
s10 = s10 + "llo";
System.out.println("s1 == s10 "+(s1 == s10));
}
}
在前面的代码中 s7 == s8 和 s1 == s10 给出 false。有人可以解释一下, s7 = s7.concat ("llo"); 中实际发生了什么吗? s10 = s10 + “llo”;我理解 == 运算符检查引用,而 equal() 检查对象的内容。但我需要知道为什么 s7 和 s10 参考变量位模式与 s8 和 s1 不同。如果这些事情与编译时生成的字符串和运行时生成的字符串有关,那么我如何识别它是编译时还是运行时字符串?
public class Demo {
public static void main(String[] args) {
String s1 = "Hello";
String s2 = "Hello";
System.out.println("s1 == s2 " + (s1 == s2));
String s5 = "Hel" + "lo";
String s6 = "He" + "llo";
System.out.println("s5 == s6 " + (s5 == s6));
String s7 = "He";
String s8 = "Hello";
s7 = s7.concat("llo");
System.out.println("s7 == s8 " + (s7 == s8));
String s10 = "He";
s10 = s10 + "llo";
System.out.println("s1 == s10 "+(s1 == s10));
}
}
In the preceding code s7 == s8 and s1 == s10 give false. Can someone please explain me, what is actually happened here in s7 = s7.concat ("llo"); and s10 = s10 + "llo"; I understand == operator checks reference and equal() checks content of object. But I need to know why s7 and s10 reference variables bit patterns are different from s8 and s1. If these things are related with compile time generated strings and run time generated strings then how can I identify whether it is compile time or run time string?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
发生这种情况的原因是 Java 在编译器中进行了优化。当它发现您将文字字符串
"Hello"
分配给 s1 时,它会对 s2 使用相同的“Hello”,因为所有 Java 字符串操作都是非破坏性的(例如,它们返回一个克隆而不是而不是修改原始版本),所以这是一个安全的做法。"Hel" + "lo"
与"He" + "llo"
也是如此;它足够聪明,能够发现它们是同一件事。其他的太复杂,无法优化它们,因此最终会得到单独的对象。
The reason this is happening is because Java is optimizing in the compiler. When it sees that you're assigning the literal string
"Hello"
to s1, it uses the same "Hello" for s2, since all Java String operations are non-destructive (eg they return a clone rather than modify the original), so that's a safe thing to do.Same thing goes for
"Hel" + "lo"
vs"He" + "llo"
; it's clever enough to figure out that they're the same thing.The others are complex enough that it can't optimize them, and thus you end up with separate objects.
== 不检查位模式,它会比较对象的内存地址。只有同一个对象才具有相同的内存地址。
== doesn't check bit patterns, it will compare memory address for objects. Only the same object has the same memory address.
克林特的答案很好,但我将进一步扩展并在编译器级别进行解释。
如您所知,
s1
和s2
最终将成为对同一字符串实例"Hello"
的引用。对于
s5
和s6
,编译器会看到常量表达式。也就是说,它看到两个常量(字符串文字)之间的运算。编译器知道如何添加字符串以及结果是什么。由于这些值在编译时立即已知,因此它会为您进行加法,从而生成文字字符串"Hello"
。因此,它与s1
和s2
具有相同的值,因此它们也将引用相同的实例。s7
不能以同样的方式简化。当然,s7
最初以“He”
开头。这里的区别在于s7 = s7.concat("llo");
将s7
重新分配给函数调用的结果。这不能按原样简化。就Java编译器而言,所有函数调用的结果在编译时都是未知的。由于它不知道结果值,因此无法对其进行简化并保持原样。结果调用返回"Hello"
字符串的新实例,该实例与编译时实例(s8
共享)不是同一个实例。s10
也不能以同样的方式简化。当然,s10
最初以“He”
开头。然后重新赋值s10 = s10 + "llo";
这无法简化。你可能会问为什么?那么s10
是一个非最终变量表达式。从技术上讲,编译器不知道它的值,因为它不是常量。如果s10
被声明为final String
,那么这可以是常量折叠(当分配给不同的变量时)。因此,请考虑这个版本的测试代码:
您能找出哪些行是正确的吗?
真,真,假,假,假,真,假
您可能想知道为什么 3 和 7 不正确。简短的回答,Java 编译器没有编程
足够聪明,能够识别 concat() 调用,因此被视为常规函数调用。
Clint's answer is fine but I'll expand on it further and explain at the compiler level.
As you know,
s1
ands2
will end up being references to the same string instance,"Hello"
.For
s5
ands6
, the compiler sees constant expressions. That is, it sees an operation between two constants (the string literals). The compiler knows how to add strings and what the result would be. Since the values are known immediately at compile time, it does the addition for you, resulting in the literal string"Hello"
. Consequently, it has the same value ass1
ands2
so each will refer to the same instance as well.s7
cannot be simplified the same way.s7
initially starts with"He"
of course. The difference here is thats7 = s7.concat("llo");
as reassignings7
to the result of a function call. This could not be simplified as is. As far as the Java compiler is concerned, the results of all function calls are not known at compile time. Since it doesn't know the resulting value, it cannot be simplified and is left as is. The resulting call returns a new instance of a"Hello"
string which is not the same instance as the compile-time instance (whichs8
shares).s10
cannot be simplified the same way as well.s10
initially starts with"He"
of course. Then is reassigneds10 = s10 + "llo";
This could not be simplified. Why you might ask? Wells10
is a non-final variable expression. Meaning technically, the compiler doesn't know it's value because it isn't a constant. Ifs10
was declared afinal String
, then this could be constant folded (when assigned to a different variable).So consider this version of your test code:
Can you figure out which lines are true?
true, true, false, false, false, true, false
You might be wondering why the 3 and 7 aren't true. Short answer, the Java compiler wasn't programmed
to be smart enough to recognize the concat() call so is treated as a regular function call.
等于运算符测试引用是否相同(即指向同一对象),而不是测试引用的值是否相同。如果您需要测试一个字符串是否等于另一个字符串,您应该使用内置的 .equals 方法。这将进行对象值比较。例如,
另外为了安全起见,如果您确实比较两个字符串并且其中一个是常量,通常最好对常量调用 equals,即而不是
原因
是第二种形式存在空指针异常的风险,可以通过调用 equals() 来避免在保证存在的常量字符串上。
The equals operator tests if the references are the same (i.e. pointing at the same object), not if the values of the references are the same. If you need to test if one string equals another you should use the built-in .equals method. This will do a object value comparison. e.g.
Additionally for safety's sake if you do compare two strings and one is a constant, it's usually best to invoke equals on the constant, i.e.
Rather than
The reason is the second form risks a null pointer exception which can be avoided by invoking equals() on the constant string which is guaranteed to be there.
您不能对字符串对象做出任何假设。
虚拟机可以努力确保不会同时存在两个包含完全相同的字符数组的字符串对象,而其他虚拟机则允许重复。
You cannot make any assumption about string objects.
A VM could work hard to make sure that no two string objects containing exactly the same char array exist at the same time, while other VMs would allow duplicates.
==
运算符仅检查两个对象是否具有相同的地址(指针)。仅对于不是引用的原始类型(如 int、char 等),它才会比较值。您需要使用诸如 s1.equals(s2) 之类的东西来比较两个字符串的内容。
The
==
operator only checks to see if two objects have the same address (pointer). Only for primitive types that aren't a referenece (like int, char, etc.) does it compare the value.You need to use something like
s1.equals(s2)
to compare the contents of two strings.在您提供的示例中,正在发生的情况是:
In the example you provided this is what is happening: