4

Recently in a job interview I was asked this following question (for Java):

Given:

String s1 = "abc";
String s2 = "abc";

What is the return value of

(s1 == s2)

I answered with it would return false because they are two different objects and == is a memory address comparison rather than a value comparison, and that one would need to use .equals() to compare String objects. I was however told that although the .equals(0 methodology was right, the statement nonetheless returns true. I was wondering if someone could explain this to me as to why it is true but why we are still taught in school to use equals()?

KWJ2104
  • 1,959
  • 6
  • 38
  • 53

7 Answers7

8

String constants are interned by your JVM (this is required by the spec as per here):

All literal strings and string-valued constant expressions are interned. String literals are defined in §3.10.5 of the Java Language Specification

This means that the compiler has already created an object representing the string "abc", and sets both s1 and s2 to point to the same interned object.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • 2
    +1 for citing the JLS. Contrary to what some of the other answers seem to imply, this behaviour is **guaranteed** for String literals. – Stephen C Feb 26 '12 at 05:35
5

java will intern both strings, since they both have the same value only one actual string instance will exist in memory - that's why == will return true - both references point to the same instance.

String interning is an optimization technique to minimize the number of string instances that have to be held in memory. String literals or strings that are the values of constant expressions, are interned so as to share unique instances. Think flyweight pattern.

BrokenGlass
  • 158,293
  • 28
  • 286
  • 335
  • Slightly inaccurate. Interning happens for **compile time constant expressions** (CTCEs) ... not for expressions that are just constant at runtime. There are specific rules in the JLS that say what a CTCE is. For instance, any method call in an expression, means that it is not a CTCE. – Stephen C Feb 27 '12 at 04:31
2

Since you are not actually creating new instances of String objects for either one of these, they are sharing the same memory space. If it were String s1 = new String("abc"); String s2 = new String("abc"); the result would be false.

Brad Cathey
  • 126
  • 1
  • 7
2

The reason is strings are interned in Java. String interning is a method of storing only one copy of each distinct string value which is immutable. Interning string makes some string processing tasks more efficient. The distinct values are stored in a string intern pool. (From wiki)

user1229441
  • 344
  • 4
  • 11
1

You're right that == uses memory address. However when the java compiler notices that you're using the same string literal multiple times in the same program, it won't create the same string multiple times in memory. Instead both s1 and s2 in your example will point to the same memory. This is called string interning.

So that's why == will return true in this case. However if you read s2 from a file or user input, the string will not automatically interned. So now it no longer points to the same memory. Therefor == would now return false, while equals returns true. And that's why you shouldn't use ==.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
0

Quick and dirty answer: Java optimizes strings so if it encounters the same string twice it will reuse the same object (which is safe because String is immutable).

However, there is no guarantee.

What usually happens is that it works for a long time, and then you get a nasty bug that takes forever to figure out because someone changed the class loading context and your == no longer works.

ptyx
  • 4,074
  • 1
  • 19
  • 21
  • 2
    This answer is misleading. 1) For String literals, it is guaranteed that interning **will** happen. 2) For other Strings, this will only happen if application or library code *explicitly* interns the String object. The JVM / JIT does not optimize this. Whenever there is a call to `new String(...)` in your code or in library code, the JLS requires that it produces a new String object. – Stephen C Feb 26 '12 at 05:40
  • Agreed (as I said, it's a quick and dirty answer). Bottom line: don't do it, if you need to rely on it your probably being to smart for your own good or the good of other people changing your code later. – ptyx Feb 26 '12 at 18:39
0

You should continue to use equals() when testing string equality. Java makes no guarantees about identity testing for strings unless they are interned. The reason the s1 == s2 in your example is because the compiler is simply optimizing 2 literal references in a scope it can predict.

velohomme
  • 136
  • 2
  • 9
  • This is misleading. 1) The "compiler" is not "simply optimizing ...". It is implementing the specified semantics of the Java language. 2) In fact, this isn't done by the compiler at all. The interning is performed by the JVM when it **loads** the class. – Stephen C Feb 27 '12 at 04:24