java 当 "" == s 为假但 "".equals( s ) 为真时
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1111296/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When "" == s is false but "".equals( s ) is true
提问by OscarRyz
EDITThanks for the prompt responses. Please see what the real question is. I have made it bold this time.
编辑感谢您的及时回复。请看看真正的问题是什么。这次我大胆了。
I do understand the difference between == and .equals. So, that's not my question (I actually added some context for that)
我确实理解 == 和 .equals 之间的区别。所以,这不是我的问题(我实际上为此添加了一些上下文)
I'm performing the validation below for empty strings:
我正在对空字符串执行以下验证:
if( "" == value ) {
// is empty string
}
In the pastwhen fetching values from the db or deserializing objects from another node, this test failed, because the two string instances were indeed different object references, albeit they contained the same data.
在过去的从数据库中获取的值或者从另一个节点反序列化对象时,本次测试失败,因为这两个字符串实例确实不同对象的引用,尽管它们含有相同的数据。
So the fix for those situations was
所以这些情况的解决方法是
if( "".equals( value ) ) {
// which returns true for all the empty strings
}
I'm fine with that. That's clearly understood.
我没问题。这很清楚。
Today this happened once again, but it puzzled me because this time the application is a very small standalone applicationthat doesn't use network at all, so no new string is fetched from the database nor deserizalized from another node.
今天再次发生这种情况,但让我感到困惑,因为这次应用程序是一个非常小的独立应用程序,根本不使用网络,因此没有从数据库中获取新字符串,也没有从另一个节点反序列化。
So the question is:
所以问题是:
Under which OTHERcircumstances:
在哪些其他情况下:
"" == value // yields false
and
和
"".equals( value ) // yields true
For a local standalone application?
对于本地独立应用程序?
I'm pretty sure new String()is not being used in the code.
我很确定new String()没有在代码中使用。
And the only way a string reference could be "" is because it is being assigned "" directly in the code (or that's what I thought) like in:
并且字符串引用可能是 "" 的唯一方法是因为它直接在代码中被分配了 ""(或者这就是我的想法),例如:
String a = "";
String b = a;
assert "" == b ; // this is true
Somehow (after reading the code more I have a clue) two different empty string object references were created, I would like to know how
不知何故(在阅读更多代码后我有一个线索)创建了两个不同的空字符串对象引用,我想知道如何
More in the line of jjnguys answer:
更多关于 jjnguys 的回答:
Byte!
字节!
EDIT: Conclusion
编辑:结论
I've found the reason.
我已经找到原因了。
After jjnguy suggestion I was able to look with different eyes to the code.
在 jjnguy 建议之后,我能够用不同的眼光看待代码。
The guilty method: StringBuilder.toString()
有罪的方法:StringBuilder.toString()
A new String object is allocated and initialized to contain the character sequence currently represented by this object.
分配并初始化一个新的 String 对象,以包含该对象当前表示的字符序列。
Doh!...
呸!...
StringBuilder b = new StringBuilder("h");
b.deleteCharAt( 0 );
System.out.println( "" == b.toString() ); // prints false
Mystery solved.
谜团已揭开。
The code uses StringBuilder to deal with an ever growing string. It turns out that at some point somebody did:
该代码使用 StringBuilder 来处理不断增长的字符串。事实证明,在某些时候有人做了:
public void someAction( String string ) {
if( "" == string ) {
return;
}
deleteBankAccount( string );
}
and use
并使用
someAction( myBuilder.toString() ); // bug introduced.
p.s. Have I read too much CodingHorror lately? Or why do I feel the need to add some funny animal pictures here?
ps 我最近读了太多 CodingHorror 了吗?或者为什么我觉得有必要在这里添加一些有趣的动物图片?
采纳答案by jjnguy
String s = "";
String s2 = someUserInputVariale.toLowercase(); // where the user entered in ""
Something like that would cause s == s2to evaluate to false.
类似的事情会导致s == s2评估为假。
Lots of code sill create new Stringswithout exposing the call to new String().
许多代码仍然会在Strings不公开调用的情况下创建新的new String().
回答by Bill the Lizard
"" == value // yields false
and
和
"".equals( value ) // yields true
any time the value of the variable valuehas not been interned. This will be the case if the value is computed at run time. See the JLS section 3.10.5 String Literalsfor example code illustrating this:
任何时候变量的值value还没有被实习。如果该值是在运行时计算的,就会出现这种情况。请参阅JLS 部分 3.10.5 String Literals以获取说明此内容的示例代码:
Thus, the test program consisting of the compilation unit (§7.3):
package testPackage; class Test { public static void main(String[] args) { String hello = "Hello", lo = "lo"; System.out.print((hello == "Hello") + " "); System.out.print((Other.hello == hello) + " "); System.out.print((other.Other.hello == hello) + " "); System.out.print((hello == ("Hel"+"lo")) + " "); System.out.print((hello == ("Hel"+lo)) + " "); System.out.println(hello == ("Hel"+lo).intern()); } } class Other { static String hello = "Hello"; }and the compilation unit:
package other; public class Other { static String hello = "Hello"; }produces the output:
true true true true false trueThis example illustrates six points:
- Literal strings within the same class (§8) in the same package (§7) represent references to the same String object (§4.3.1).
- Literal strings within different classes in the same package represent references to the same String object.
- Literal strings within different classes in different packages likewise represent references to the same String object.
- Strings computed by constant expressions (§15.28) are computed at compile time and then treated as if they were literals.
- Strings computed at run time are newly created and therefore distinct.
- The result of explicitly interning a computed string is the same string as any pre-existing literal string with the same contents.
因此,由编译单元(第 7.3 节)组成的测试程序:
package testPackage; class Test { public static void main(String[] args) { String hello = "Hello", lo = "lo"; System.out.print((hello == "Hello") + " "); System.out.print((Other.hello == hello) + " "); System.out.print((other.Other.hello == hello) + " "); System.out.print((hello == ("Hel"+"lo")) + " "); System.out.print((hello == ("Hel"+lo)) + " "); System.out.println(hello == ("Hel"+lo).intern()); } } class Other { static String hello = "Hello"; }和编译单元:
package other; public class Other { static String hello = "Hello"; }产生输出:
true true true true false true这个例子说明了六点:
- 同一包(第 7 节)中同一类(第 8 节)中的文字字符串表示对同一字符串对象(第 4.3.1 节)的引用。
- 同一包中不同类中的文字字符串表示对同一 String 对象的引用。
- 不同包中不同类中的文字字符串同样表示对同一 String 对象的引用。
- 由常量表达式(第 15.28 节)计算的字符串在编译时计算,然后将它们视为文字。
- 在运行时计算的字符串是新创建的,因此是不同的。
- 显式插入计算字符串的结果是与任何具有相同内容的预先存在的文字字符串相同的字符串。
回答by Tom
If you can grab a hold of the book Java Puzzlersby Joshua Bloch and Neal Gafter, and look at puzzle 13, "Animal Farm"... he has great advice on this issue. I am going to copy some relevant text:
如果您能拿到Joshua Bloch 和 Neal Gafter所著的Java Puzzlers一书,并查看谜题 13,“Animal Farm”……他对这个问题有很好的建议。我要复制一些相关的文字:
"You may be aware that compile-time constants of type Stringare interned[JLS 15.28]. In other words any two constant expressionsof type Stringthat designate the same character sequence are represented by identical object references... Your code should rarely, if ever, depend on the interning of string constants.Interning was designed solely to reduce the memory footprint of the virtual machine, not as a tool for programmers... When comparing object references, you should use the equalsmethod in preference to the ==operatorunless you need to compare object identity rather than value."
“您可能知道类型的编译时常量String是内部常量[JLS 15.28]。换句话说,指定相同字符序列的任何两个类型的常量表达式String都由相同的对象引用表示......你的代码应该很少,如果有的话,依赖于字符串常量的实习。实习的目的只是为了减少虚拟机的内存占用,不作为程序员的工具......当比较对象引用,你应该使用的equals方法优先于==运营商,除非你需要比较对象身份而不是价值。”
That's from the above reference I mentioned... pages 30 - 31 in my book.
那是我提到的上述参考资料......我书中的第 30 - 31 页。
回答by djna
Would you expect "abcde".substring(1,2)and "zbcdefgh".substring(1,2)to yield the same String object?
您会期望"abcde".substring(1,2)并"zbcdefgh".substring(1,2)产生相同的 String 对象吗?
They both yield "equal" sub-strings extracted from two different Strings, but it seems quite reasonable that tehy are different objects, so == sees them as different.
它们都产生从两个不同的字符串中提取的“相等”的子字符串,但是 tehy 是不同的对象似乎很合理,所以 == 将它们视为不同的。
Now consider when the substring has length 0, substring(1, 1). It yields a zero length String, but it's not surprising that the "abcde".substring(1,1)is a different object from "zbcdefgh".substring(1,2)and hence at least one of them is a different object from "".
现在考虑当子串的长度为 0, 时 substring(1, 1)。它产生一个零长度的字符串,但它"abcde".substring(1,1)是一个不同的对象也就不足为奇了"zbcdefgh".substring(1,2),因此其中至少一个是与“”不同的对象。
回答by Janusz
As I understand it while compiling the Java code to bytecode or while running the program same strings will be referenced to the same object in the most cases to save memory. So sometimes you get away with == comparisons of strings. But this is a compiler optimization you can not rely on.
据我了解,在将 Java 代码编译为字节码或运行程序时,在大多数情况下将引用相同的字符串以节省内存。所以有时你会逃避字符串的 == 比较。但这是您不能依赖的编译器优化。
But then sometimes it happens that the compiler decides to not do this optimization or there is no way for the program to see that the strings are the same and out of the sudden the check fails since you are relying on some underlying optimization voodoo that depends on implementation of the jvm you are using and so on.
但是有时会发生编译器决定不进行此优化或程序无法看到字符串相同并且突然检查失败的情况,因为您依赖于某些依赖于的底层优化伏都教您正在使用的 jvm 的实现等等。
So using equals is always the good thing to do. For empty strings there are other possibilities like comparing with length == 0 or if you don't care about backwards compatibility there is string.empty().
所以使用equals总是好的。对于空字符串,还有其他可能性,例如与 length == 0 进行比较,或者如果您不关心向后兼容性,则可以使用 string.empty()。
回答by Paul Sonier
You should try considering String.length() == 0.
你应该尝试考虑String.length() == 0。
回答by JeeBee
Why not use:
为什么不使用:
if (value != null && value.length == 0) {
// do stuff (above could be "== null ||"
}
You should use equals()because ==for objects compares references, i.e., are they the same object. Whilst at compile time Java finds identical strings and makes them share the same reference (Strings are immutable), at runtime it is easy to create empty strings that have different references, where == fails for your typical intention of equals().
您应该使用equals(),因为==对于比较对象引用,即,它们是同一个对象。虽然在编译时 Java 会找到相同的字符串并使它们共享相同的引用(字符串是不可变的),但在运行时很容易创建具有不同引用的空字符串,其中 == 无法满足您的典型意图equals()。
回答by artlung
Check this reference: http://mindprod.com/jgloss/string.html#COMPARISONat the excellent Canadian Mind Products Java & Internet Glossary. Worth a bookmark.
检查此参考:http: //mindprod.com/jgloss/string.html#COMPARISON在优秀的Canadian Mind Products Java & Internet Glossary 中。值得收藏。
回答by Alex B
The javadocfor String.intern()has some good commentary on ==vs. .equals().
该javadoc的用于String.intern()对一些好的评论==对.equals()。
The documentation also clarifies that every string literal is intern'd.
该文档还阐明了每个字符串文字都是intern'd。
public String intern()
Returns a canonical representation for the string object.
A pool of strings, initially empty, is maintained privately by the class String.
When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.
It follows that for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true.
All literal strings and string-valued constant expressions are interned. String literals are defined in §3.10.5 of the Java Language Specification
Returns: a string that has the same contents as this string, but is guaranteed to be from a pool of unique strings.
公共字符串实习生()
返回字符串对象的规范表示。
字符串池最初是空的,由 String 类私下维护。
当调用 intern 方法时,如果池中已经包含一个等于该 String 对象的字符串(由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中并返回对此 String 对象的引用。
因此,对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为真时,s.intern() == t.intern() 为真。
所有文字字符串和字符串值常量表达式都被实习。字符串文字在 Java 语言规范的 §3.10.5 中定义
返回: 与此字符串具有相同内容的字符串,但保证来自唯一字符串池。
回答by Trevor Harrison
If you use google code search, you can find lots of places where people make this same error: google for file:.java \=\=\ \"\"Of course, this can be a correct idiom in carefully controlled circumstances, but usually, its just a bug.
如果你使用谷歌代码搜索,你会发现很多地方人们会犯同样的错误:google for file:.java \=\=\ \"\"当然,在仔细控制的情况下这可能是一个正确的习语,但是通常,它只是一个错误。

