tags:

views:

326

answers:

8
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) ?

+16  A: 

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
Aren't the strings interned, so it actually evaluates to true?
Winston Smith
@Winston Smith: The literals are interned, but `s` is assigned the return value of a constructor call.
Jon Skeet
@Winston: If they are it will be the same object, but where do you see a call to intern() in the question?
Fredrik
true, as per the third bullet
Jon Skeet
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
@Paul: No, but I'll add to my answer to say why you *might* want to call that constructor...
Jon Skeet
@Downvoter: Care to explain the downvote? Where have I gone wrong?
Jon Skeet
@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
@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
@Downvoter: Care to give a reason?
Jon Skeet
+1  A: 

== 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 Benthin
can be more specific, because i know it does not compare the content.
Hari
A: 

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

jose
-1: Java does not have operator overloading.
Simon Nickerson
um, except for + on Strings I guess :-)
Simon Nickerson
A: 

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
+1  A: 

Hi Hari, 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.
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
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.
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.
@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
@Jon : Can you please give an example.
Geek
@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
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
Hari
+1  A: 
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
+1  A: 

== 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
A: 

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.

Dave