Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

== operator with Strings

Tags:

The code below should not print "Bye", since == operator is used to compare references, but oddly enough, "Bye" is still printed. Why does this happen? I'm using Netbeans 6.9.1 as the IDE.

public class Test {     public static void main(String [] args) {         String test ="Hi";         if(test=="Hi"){             System.out.println("Bye");         }     } } 
like image 573
OckhamsRazor Avatar asked Jul 05 '11 07:07

OckhamsRazor


People also ask

Can you use == for Strings in C?

In C, string values (including string literals) are represented as arrays of char followed by a 0 terminator, and you cannot use the == operator to compare array contents; the language simply doesn't define the operation.

Can we use == operator for Strings in C++?

In C++ the == operator is overloaded for the string to check whether both strings are same or not. If they are the same this will return 1, otherwise 0. So it is like Boolean type function.

Can you use == for strings in Java?

To compare these strings in Java, we need to use the equals() method of the string. You should not use == (equality operator) to compare these strings because they compare the reference of the string, i.e. whether they are the same object or not.

What operators work with strings?

A couple of the operators that you use on numeric operands can be applied to strings as well—the operator that looks like a plus sign ( + ), which in this case is considered the concatenation operator, and the multiplication sign operator ( * ), which with strings is considered the replication operator.


2 Answers

This behavior is because of interning. The behavior is described in the docs for String#intern (including why it's showing up in your code even though you never call String#intern):

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.

So for example:

public class Test {      private String s1 = "Hi";      public static void main(String [] args) {          new Test().test();         System.exit(0);     }      public void test() {         String s2 ="Hi";         String s3;          System.out.println("[statics]          s2 == s1? " + (s2 == s1));         s3 = "H" + part2();         System.out.println("[before interning] s3 == s1? " + (s3 == s1));         s3 = s3.intern();         System.out.println("[after interning]  s3 == s1? " + (s3 == s1));         System.exit(0);     }      protected String part2() {         return "i";     } } 

Output:

[statics]          s2 == s1? true [before interning] s3 == s1? false [after interning]  s3 == s1? true

Walking through that:

  1. The literal assigned to s1 is automatically interned, so s1 ends up referring to a string in the pool.
  2. The literal assigned to s2 is also auto-interned, and so s2 ends up pointing to the same instance s1 points to. This is fine even though the two bits of code may be completely unknown to each other, because Java's String instances are immutable. You can't change them. You can use methods like toLowerCase to get back a new string with changes, but the original you called toLowerCase (etc.) on remains unchanged. So they can safely be shared amongst unrelated code.
  3. We create a new String instance via a runtime operation. Even though the new instance has the same sequence of characters as the interned one, it's a separate instance. The runtime doesn't intern dynamically-created strings automatically, because there's a cost involved: The work of finding the string in the pool. (Whereas when compiling, the compiler can take that cost onto itself.) So now we have two instances, the one s1 and s2 point to, and the one s3 points to. So the code shows that s3 != s1.
  4. Then we explicitly intern s3. Perhaps it's a large string we're planning to hold onto for a long time, and we think it's likely that it's going to be duplicated in other places. So we accept the work of interning it in return for the potential memory savings. Since interning by definition means we may get back a new reference, we assign the result back to s3.
  5. And we can see that indeed, s3 now points to the same instance s1 and s2 point to.
like image 114
T.J. Crowder Avatar answered Oct 26 '22 07:10

T.J. Crowder


Hard-coded Strings are compiled into the JVM's String Table, which holds unique Strings - that is the compiler stores only one copy of "Hi", so you are comparing that same object, so == works.

If you actually create a new String using the constructor, like new String("Hi"), you will get a different object.

like image 41
Bohemian Avatar answered Oct 26 '22 09:10

Bohemian