5
public static void main(String [] a)
{
    String s = new String("Hai");
    String s1=s;
    String s2="Hai";
    String s3="Hai";
    System.out.println(s.hashCode());
    System.out.println(s1.hashCode());
    System.out.println(s2.hashCode());
    System.out.println(s3.hashCode());
    System.out.println(s==s2);
    System.out.println(s2==s3);

}

From the above code can anyone explain what is going behind when JVM encounters this line (s==s2) ?

Hariharbalaji
  • 2,498
  • 8
  • 36
  • 51

8 Answers8

17

It compares references - i.e. are both variables referring to the exact same object (rather than just equal ones).

  • s and s2 refer to different objects, so the expression evaluates to false.
  • s and s1 refer to the same objects (as each other) because of the assignment.
  • s2 and s3 refer to the same objects (as each other) because of string interning.

If that doesn't help much, please ask for more details on a particular bit. Objects and references can be confusing to start with.

Note that only string literals are interned by default... so even though s and s2 refer to equal strings, they're still two separate objects. Similarly if you write:

String x = new String("foo");
String y = new String("foo");

then x == y will evaluate to false. You can force interning, which in this case would actually return the interned literal:

String x = new String("foo");
String y = new String("foo");
String z = "foo";

// Expressions and their values:
x == y: false
x == z: false
x.intern() == y.intern(): true
x.intern() == z: true

EDIT: A comment suggested that new String(String) is basically pointless. This isn't the case, in fact.

A String refers to a char[], with an offset and a length. If you take a substring, it will create a new String referring to the same char[], just with a different offset and length. If you need to keep a small substring of a long string for a long time, but the long string itself isn't needed, then it's useful to use the new String(String) constructor to create a copy of just the piece you need, allowing the larger char[] to be garbage collected.

An example of this is reading a dictionary file - lots of short words, one per line. If you use BufferedReader.readLine(), the allocated char array will be at least 80 chars (in the standard JDK, anyway). That means that even a short word like "and" takes a char array of 160 bytes + overheads... you can run out of space pretty quickly that way. Using new String(reader.readLine()) can save the day.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    Aren't the strings interned, so it actually evaluates to true? – Winston Smith Dec 11 '09 at 12:06
  • 3
    @Winston Smith: The literals are interned, but `s` is assigned the return value of a constructor call. – Jon Skeet Dec 11 '09 at 12:08
  • @Winston: If they are it will be the same object, but where do you see a call to intern() in the question? – Fredrik Dec 11 '09 at 12:08
  • true, as per the third bullet – Jon Skeet Dec 11 '09 at 12:10
  • 1
    You should add a comment to your answer to say that you almost never want to do new String(String), since you already have a String to start off with, and creating the new String is only using extra memory. Other than that, excellent answer! – Paul Wagland Dec 11 '09 at 12:23
  • @Paul: No, but I'll add to my answer to say why you *might* want to call that constructor... – Jon Skeet Dec 11 '09 at 12:34
  • @Downvoter: Care to explain the downvote? Where have I gone wrong? – Jon Skeet Dec 11 '09 at 12:37
  • @Jon, agreed that this is a valid usecase ;-) I perhaps should have said that new String(unalteredString) is useless, and, in my defence, I say that you "almost never" want to do this. However, I often see the exact code that was in the question: String s1 = new String("string"); and that is a waste. – Paul Wagland Dec 11 '09 at 12:44
  • @Paul: I agree that creating a new string for a literal is a bad idea. You *could* use it if you wanted a unique reference to lock on, but use the string value for debugging... but I'd create a separate type for that. – Jon Skeet Dec 11 '09 at 12:54
  • There is a subtlety to using `new String(String)`; see http://stackoverflow.com/a/390854/8946. – Lawrence Dol Jan 11 '13 at 00:56
1

== compars objects not the content of an object. s and s2 are different objects. If you want to compare the content use s.equals(s2).

Marcel B
  • 3,624
  • 2
  • 27
  • 39
1

I suppose you know that when you test equality between variables using '==', you are in fact testing if the references in memory are the same. This is different from the equals() method that combines an algorithm and attributes to return a result stating that two Objects are considered as being the same. In this case, if the result is true, it normally means that both references are pointing to the same Object. This leaves me wondering why s2==s3 returns true and whether String instances (which are immutable) are pooled for reuse somewhere.

James P.
  • 19,313
  • 27
  • 97
  • 155
  • 2
    String Objects are created on demand. If a String already exists the new Reference points to the same Object rather than creating a new String Object. See my answer below. However the statement doesnot apply to Objects created with new String(). – Geek Dec 11 '09 at 12:17
  • 1
    Thanks for the explanation. So if I do this: String s1 = new String("a string"); String s2 = new String("a string"); s1 and s2 point to the same instance ? I'm assuming here that String allocation is equivalent whether you explicitely instantiate a String or use autoboxing. – James P. Dec 11 '09 at 12:24
  • Ah right, now I understand. If you use a new String(), you are explicitely forcing the creation of a new instance. That's the sort of trivia you can pull out at a job interview. – James P. Dec 11 '09 at 12:30
  • @Geek: It's broader than "it doesn't apply to objects created with new String" - it doesn't apply (automatically) to *anything* other than string literals. – Jon Skeet Dec 11 '09 at 12:38
  • @Jon : Can you please give an example. – Geek Dec 11 '09 at 12:46
  • @Geek: How about: `String y = x.substring(1, 2); String z = x.substring(1, 2);` Now `y` and `z` will refer to different string instances, but there's no "new String" in user-visible code. It's much easier to talk about what's *different* about string literals than making a broad statement of "String objects are created on demand". – Jon Skeet Dec 11 '09 at 12:56
  • so by typing String s1=new String("a string"); String s2 = new String("a string"); i am creating two objects explicitly so both the references will be different and by giving String s3="new"; and String s4="new"; i am referring s2,s3 to same data. Thats why s1==s2 is false and s3==s4 is true correct me if i am wrong – Hariharbalaji Dec 12 '09 at 09:56
1
Think of it like this.
  Identical twins look the same but they are made up differently.
If you want to know if they "look" the same use the compare.
If you want to know they are a clone of each other use the "=="

:)
Brad8118
  • 4,672
  • 11
  • 36
  • 48
1

== compares the memory (reference) location of the Objects. You should use .equals() to compare the contents of the object.

You can use == for ints and doubles because they are primitive data types

twodayslate
  • 2,803
  • 3
  • 27
  • 43
0

It should be an obvious false. JVM does a thing like using the strings that exist in the Memory . Hence s2,s3 point to the same String that has been instantiated once. If you do something like s5="Hai" even that will be equal to s3.

However new creates a new Object. Irrespective if the String is already exisitng or not. Hence s doesnot equal to s3,s4.

Now if you do s6= new String("Hai"), even that will not be equal to s2,s3 or s.

Geek
  • 23,089
  • 20
  • 71
  • 85
0

The literals s2 and s3 will point to the same string in memory as they are present at compile time. s is created at runtime and will point to a different instance of "Hai" in memory. If you want s to point to the same instance of "Hai" as s2 and s3 you can ask Java to do that for you by calling intern. So s.intern == s2 will be true.

Good article here.

David
  • 1,862
  • 2
  • 22
  • 35
-3

You are using some '==' overload for String class...

jose
  • 2,733
  • 4
  • 37
  • 51