开发者

Strings in Java : equals vs == [duplicate]

This question already has answers here: 开发者_如何学运维 Closed 9 years ago.

Possible Duplicate:

How do I compare strings in Java?

  String s1 = "andrei";
  String s2 = "andrei";

  String s3 = s2.toString();

  System.out.println((s1==s2) + " " + (s2==s3));

Giving the following code why is the second comparison s2 == s3 true ? What is actually s2.toString() returning ? Where is actually located (s2.toString()) ?


First of all String.toString is a no-op:

/**
 * This object (which is already a string!) is itself returned.
 *
 * @return  the string itself.
 */
public String toString() {
    return this;
}

Second of all, String constants are interned so s1 and s2 are behind the scenes changed to be the same String instance.


The method String.intern() can be used to ensure that equal strings have equal references. String constants are interned, so s1 and s2 will reference the same string. String.toString() simply returns itself, that is, a.toString() returns a, when a is a String. So, s2 also == s3.

In general, strings should not be compared by reference equality, but by value equality, using equals(). The reason is that it's easy to get two strings that are equivalent but different references. For example, when creating substrings. An exception to this rule is that if you know both strings have been interned beforehand (or you intern them as part of the comparison.)

To answer your implied question about heap or stack, Strings are allocated on the heap. Even if they were allocated on the stack, such as with the upcoming escape analysis and stack allocation, the semantics of the program will not change, and you will get the same result for both heap and stack allocation.


Basically when you use new String("something") you're forcing Java to create a brand new object.

When you assign to a String literal ="something", that string is stored in the constant pool, an optimization done by the JVM. So when you assign another reference to the same constant, the Object stored in the constant pool gets reused, basically, it's the same object.


You should be using .equals and not == when comparing java strings.

== Compares references and therefore s2.ToString() returns s2.

From the java glossary about heap / stack:

In Sun’s JVM, the interned Strings (which includes String literals) are

stored in a special pool of RAM called the perm gen, where the JVM also loads classes and stores natively compiled code. However, the intered Strings behave no differently than had they been stored in the ordinary object heap.


From the java virtual machine spec:

String literals and, more generally, strings that are the values of constant expressions are "interned" so as to share unique instances, using the method String.intern.

"andrei" is a String literal and therefore "interned". Therefore both String s1and s2 refer to the same String object, an interned String with the content "andrei".

Therefore (s1 == s2) && (s1.equals(s2)) is true. String#toString() doesn't create a new String (like many other methods from String) but simple returns this. Therfore s2 == s3 is true.


Why the first result is false ?

== compares references and you create two different objects.

I understood that for none primitive types, when we do '==',

A String is not a primitive. References will be == when they refer to the same object.


Given that == compares references, you can see from s2 == s3 being true that s2.toString() returns s2.


Since String are immutables, a useful implementation of the toString method is - in the String class - to return this.

As an example, my rt.jar contains the following implementation :

public String toString() {
return this;
}

As a consequence, the reference associated to s3 is the same than the one associated to s2.

Considering the s1==s2 statement, it is due to the automatic call to intern() for all constant Strings. That means that at compile time, s2 initialization code will be replaced by s2=s1, which makes the assertion quite obvious, no ?


Only interned (String.intern()) strings are safe to compare with == for all other cases you should use equals.

In your case you define your own type MyString which has small in common with java String so comparing s and s1 you compare references to two distinct objects that is why you got false.


Every instance of MyString sits in a different memory location, so, forgetting about the contents of the instances, for every two different instances the == test is going to result in false.

In case of the String class, there's a small, but important difference, when you do assignment of a String variable and the right hand side operator is a literal (i.e. String s = "foo";), a new memory location is going to be occupied by "foo" only if "foo" was not encountered before as a literal. If this is the case (i.e. String s = "foo"; String otherS = "foo";), otherS is just going to reference the already present "foo".

This behaviour is called String pooling.


When comparing s == s1 you are comparing two different MyString objects. Think of your situation like this

Strings in Java : equals vs == [duplicate]

s and s1 are different objects, but their attribute point to the same instance of toto.

They are different objects because of the way you create them:

MyString s = new MyString("toto");
MyString s1 = new MyString("toto");

So s == s1 will return false. For it to return true, they had to be the same object. You could achieve it like this:

MyString s = new MyString("toto");
MyString s1 = s;

That would be the result

Strings in Java : equals vs == [duplicate]


The reason for the first comparison to fail is, that you do create two Objects by calling new. Now, the == operator does compare two memory addresses, which yields the return you got because the two objects are not at the same memory cell.

The reason why it works with constant Strings is, that the java compiler, javac, does optimize the code. By that optimisation similar string constants are being placed in one and the same memory cell. If you would have done the following, then the result would have been the same for your String objects.

String s2 = new String("toto");
String s3 = new String("toto");
System.out.println(s2==s3); //yields false!!

Your way to go is .equals(other). For that you'll have to implement the method equals in the class Mystring:

class MyString{

    private String s;

    public MyString (String s){
        this.s = s;
    }

    public String getContent(){
        return s;
    }

    @Override
    public boolean equals(Object other){
        if(other instanceof MyString){
            MyString compareTo = (MyString) other;
            return this.s.equals(compareTo.getContent());
        }
        return false;
    }
}


"==" is compare reference. But Equals() method in Object class is compare reference only. And the behavior of method equals() in the subclass is based on the implement of overriding this method.


When you use == on strings, only the references are compared. Thus, == is only guaranteed to return true in situations like:

String s1 = "...";
String s2 = s1;    // reference assignment!

Here, s1 == s2. In all other situations, == may or may not return true even if the two strings contain the same character sequence.

To compare the contents of the two strings, use equals():

if (s1.equals(s2)) {
   ...
}


s2.toString () is returning a String representation. Since it's already a String it returns itself (thats why the comparison is true).

All Strings are allocated on the Heap, the coparison operator just compares whether they are the same object (thats why s1 != s2).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜