Can I use "==" to compare two String? :P
These days, when I'm reading some other guy's code, I encounter some problem. In these code, I can read following codes:
JButton button = new JButton("OK");
button.setActionCommand("OK");
button.addActionListener(this);
......
actionPerformed(e) {
String s = e.getActionCommand();
if(s=="OK")
......
}
Look, it use "==" but not "equals" here. "Oh, it must be a bug!", I told myself. But, wait, when I excuted the program, it worked quite well. And till this moment, I remembered, current powerful JVM will maintain a constant pool for String, so maybe two "OK" will reference the same place. So, such mechanism will work.
But, does Java Language Specification has such standard? and all JVM will follow this standard? I continue to dig into it.
First, I found such item in JLS 3.10.5 -- String literals.
Abstract some points here:
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.
So, this is the feature of String class, every JVM should follow. And, when I read the code of String.java, I found such comments in method "intern".
public String intern()
Returns a canonical representation for the string object.
A pool of strings, initially empty, is maintained privately by the class String.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~So good:-)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.
It's quite clear about the case I encountered. Then I understand, this is not a bug, but the trick :P. But, why he use "==" but not "equals", I think that will be more clear and more easy to read, I think there must be other guys to be puzzled as me :-).
I think the author must care more about the performance than the code, the performance of "==" sure if better than "equals", especially when the String is long~.
Ok, everything clear now, and sure, not only String has such pool. For example:
Integer i = 1;
Integer j = 1;
what will System.out.println(i==l) output? I think you can get the right answer. :P
( 2004年08月14日, 05:25:10 下午 GMT+08:00 ) Permalink 评论 [5]
该日志评论功能被禁用了。


Integer i = 1;
Integer j = 1;
somewhere in a method, (i==j) will yield true; But: if you do Integer i = 300;
Integer j = 300;
then it won't (at least for a current 1.5beta). The reason is the 1.5 Autboxing JLS changes, which mandate that all values between -127 and 128 (give or add 1, I never remember) must be cached at Autoboxing, ie. they will always yield the same object reference (this caching happens in the Wrapper classes). BTW: about == vs equals for Strings: I didn't know that JLS requires the same string literals to result in the same String objects even across classes and packages; but I still would use equals for string comparison;; it's not much more expensive, and (in the example you gave) the few more instructions don't even matter, as it handles a GUI event, and those only happen every eternity (at least from the CPUs point of view); And if you have loads of different events, and have a long if/elseif structure, where lots of string comparisons seem expensive, maybe refactoring this to use a Map (Command -> Handler) would be better;
发表于 murphee 在 2004年08月17日, 01:46 上午 GMT+08:00 #
Integer i = 1;
Integer j = 1;
somewhere in a method, (i==j) will yield true; But: if you do Integer i = 300;
Integer j = 300;
then it won't (at least for a current 1.5beta). The reason is the 1.5 Autboxing JLS changes, which mandate that all values between -127 and 128 (give or add 1, I never remember) must be cached at Autoboxing, ie. they will always yield the same object reference (this caching happens in the Wrapper classes). BTW: about == vs equals for Strings: I didn't know that JLS requires the same string literals to result in the same String objects even across classes and packages; but I still would use equals for string comparison;; it's not much more expensive, and (in the example you gave) the few more instructions don't even matter, as it handles a GUI event, and those only happen every eternity (at least from the CPUs point of view); And if you have loads of different events, and have a long if/elseif structure, where lots of string comparisons seem expensive, maybe refactoring this to use a Map (Command -> Handler) would be better;
发表于 murphee 在 2004年08月17日, 02:28 上午 GMT+08:00 #
Btw: Can you elaborate the issue use a map for command route?
:-)
发表于 Elan Meng 在 2004年08月17日, 02:27 下午 GMT+08:00 #
发表于 henrik Lynggaard 在 2004年09月21日, 04:42 上午 GMT+08:00 #
发表于 Elan Meng 在 2004年09月21日, 09:33 上午 GMT+08:00 #