开发者

Difference between String#equals and String#contentEquals methods

开发者 https://www.devze.com 2023-03-15 03:34 出处:网络
What is the difference between the String#equals method and the Str开发者_StackOverflowing#contentEquals method?The String#equals() not only compares the String\'s contents, but also checks if the oth

What is the difference between the String#equals method and the Str开发者_StackOverflowing#contentEquals method?


The String#equals() not only compares the String's contents, but also checks if the other object is also an instance of a String. The String#contentEquals() only compares the contents (the character sequence) and does not check if the other object is also an instance of String. It can be anything as long as it is an implementation of CharSequence which covers a.o. String, StringBuilder, StringBuffer, CharBuffer, etc.


To put it easily: String.contentEquals() is the smarter brother of String.equals(), because it can be more free in the implementation than String.equals().

There are some reasons why there is a separate String.contentEquals() method. The most important reason I think is:

  • The equals method has to be reflexive. That means that: x.equals(y) == y.equals(x). This implies that aString.equals(aStringBuffer) would have to be the same as aStringBuffer.equals(aString). This would require the Java API developers to make some special implementation for Strings in the equals() method of StringBuffer, StringBuilder and CharSequence as well. This would be a mess.

This is where String.contentEquals comes in. This is a standalone method that does not have to follow the strict requirements and rules for Object.equals. This way, you can implement the sense of "equal content" more freely. This allows you to make intelligent comparisons between a StringBuffer and a String, for example.

And to say what exactly the difference is:

  • String.contentEquals() can compare the contents of a String, a StringBuilder, a StringBuffer, a CharSequence and all derived classes of these. If the parameter is of type String, then String.equals() get executed.

  • String.equals() only compares String objects. All other object types are considered as not equal.

  • String.contentEquals() can compare StringBuffer and StringBuilder in an intelligent way. It does not call the heavy toString() method, which copies the whole content to a new String object. Instead, it compares with the underlying char[] array, which is great.


This answer was already posted by dbw but he deleted it but he had some very valid points for the difference while comparing execution time, what exceptions are thrown,

If you look at the source code String#equals and String#contentEquals it is clear that there are two overridden methods for String#contentEquals one which take StringBuilder and other CharSequence.
The difference between them,

  1. String#contentEquals will throw NPE if the argument supplied is null but String#equals will return false
  2. String#equals compares the content only when the argument supplied is instance of String otherwise it will return false in all other cases but on the other hand String#contentEquals checks the content of all the objects which implement interface CharSequence.
  3. You can also tweak the code so that String#contentEquals return the wrong result or result you want by overriding equals method of the argument passed as shown below but you can not do those tweaks with String#equals.
    Below code will always produce true as long as s contains any string which is 3 character long

        String s= new String("abc");// "abc";
        System.out.println(s.contentEquals(new CharSequence() 
        {
    
            @Override
            public CharSequence subSequence(int arg0, int arg1) {
                // TODO Auto-generated method stub
                return null;
            }
    
            @Override
            public int length() {
                // TODO Auto-generated method stub
                return 0;
            }
    
            @Override
            public char charAt(int arg0) {
                // TODO Auto-generated method stub
                return 0;
            }
    
    
            @Override
            public boolean equals(Object obj) 
            {
               return true;
            }
        }));
    
  4. String#contentEquals will be slower then String#Equals in the case when argument supplied is instance of String and the length of both String is same but contents are not equal.
    Example if the string are String s = "madam" and String argPassed = "madan" then s.contentEquals(argPassed) will take almost double execution time in this case as compared to s.equals(argPassed)

  5. If the content length are not same for both the strings then function String#contentEquals will have better performance then String#Equals in almost all possible cases.

One more point to add to his answer

  1. String#contentEquals of a String object will also compare to the StringBuilder contents and provide the appropriate result while String#Equals will return false


  • String class equals(Object o) method does only String comparison. But contentEquals(CharSequence cs) checks for classes extends AbstractStringBuilder i.e. StringBuffer, StringBuilder and String class also (They all are of type CharSequence).

    String str = "stackoverflow";
    StringBuilder builder = new StringBuilder(str);
    System.out.println(str.equals(builder));
    System.out.println(str.contentEquals(builder));
    

output:

false
true

The output of first stmt is false because builder is not of type String so equals() returns false but the contentEquals() checks for the content of all the type like StringBuilder, StringBuffer, String and as the content is same hence true.

  • contentEquals will throw NullPointerException if the argument supplied is null but equals() will return false because the equals() checks for instanceOf ( if (anObject instance of String) ) which returns false if the argument is null.


contentEquals(CharSequence cs):

  • Lets you check equality of given string value with any implementation instance of interface java.lang.CharacterSequence (eg, CharBuffer, Segment, String, StringBuffer, StringBuilder )

equals(Object anObject):

  • Lets you check equality of given string value with any instance of type java.lang.String only

RTFC :)

Since reading the source is the best way to understand it, I am sharing the implementations of both the methods (as of jdk 1.7.0_45)

public boolean contentEquals(CharSequence cs) {
    if (value.length != cs.length())
        return false;
    // Argument is a StringBuffer, StringBuilder
    if (cs instanceof AbstractStringBuilder) {
        char v1[] = value;
        char v2[] = ((AbstractStringBuilder) cs).getValue();
        int i = 0;
        int n = value.length;
        while (n-- != 0) {
            if (v1[i] != v2[i])
                return false;
            i++;
        }
        return true;
    }
    // Argument is a String
    if (cs.equals(this))
        return true;
    // Argument is a generic CharSequence
    char v1[] = value;
    int i = 0;
    int n = value.length;
    while (n-- != 0) {
        if (v1[i] != cs.charAt(i))
            return false;
        i++;
    }
    return true;
}

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String) anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                        return false;
                i++;
            }
            return true;
        }
    }
    return false;
 }

There is another method of String#contentEquals():

public boolean contentEquals(StringBuffer sb) {
    synchronized(sb) {
        return contentEquals((CharSequence)sb);
    }
}


equals() and contentEquals() are two methods in String class to compare two strings and string with StringBuffer.

The parameters of contentEquals() are StringBuffer and String(charSequence). equals() is used to compare two strings and contentEquals() is used to compare the contents of String and StringBuffer.

Method contentEquals and equals are

public boolean contentEquals(java.lang.StringBuffer);
public boolean contentEquals(java.lang.CharSequence);
public boolean equals(Object o)

Here is an code which describes both methods

public class compareString {
    public static void main(String[] args) {
        String str1 = "hello";    
        String str2 = "hello";

        StringBuffer sb1 = new StringBuffer("hello");
        StringBuffer sb2 = new StringBuffer("world");

        boolean result1 = str1.equals(str2);        // works nice and returns true
        System.out.println(" str1.equals(str2) - "+ result1);

        boolean result2 = str1.equals(sb1);         // works nice and returns false
        System.out.println(" str1.equals(sb1) - "+ result2);

        boolean result3 = str1.contentEquals(sb1);  // works nice and returns true
        System.out.println(" str1.contentEquals(sb1) - "+ result3);

        boolean result4 = str1.contentEquals(sb2);  // works nice and returns false
        System.out.println(" str1.contentEquals(sb2) - "+ result4);

        boolean result5 = str1.contentEquals(str2);  // works nice and returns true
        System.out.println(" str1.contentEquals(str2) - "+ result5);
    }
}

Output:

 str1.equals(str2) - true
 str1.equals(sb1) - false
 str1.contentEquals(sb1) - true
 str1.contentEquals(sb2) - false
 str1.contentEquals(str2) - true


The contentEquals() method checks is the contents are same between a String, StringBuffer, etc which some kind of char sequence.


String#equals takes Object as an argument and checks it is instance of String object or not. If the argument object is String Object then it compares content character by character. It returns true in case content of both string objects are same.

String#contentEquals takes CharSequence interface as an argument. CharSequence can be implements in 2 ways-by using i) String class or (ii) AbstractStringBuilder( parent class of StringBuffer, StringBuilder)

In contentEquals() length is compared before any object instance check. If length is same then it checks argument object is instance of AbstractStringBuilder or not. If it is so(i.e. StringBuffer or StringBuilder ) then content is checked character by character. In case argument is an instance of String object then String#equals called from String#contentEquals.

So in short,

String#equals compares the content character by character in case argument is String object also. And String#contentEquals compares the content in case argument object implement CharSequence interface.

String#contentEquals is slower in case we compare two same length string content as String#contentEquals internally calls String#equals for String object.

In case we try to compare objects with difference content length (say "abc" with "abcd") then String#contentEquals is faster than String#equals. Because length is compared before any object instance checking.


BTW, the historical reason for the difference is that String originally had no superclass, so String.equals() takes a String as its argument. When CharSequence was introduced as the superclass of String, it needed an equality test of its own that worked across all CharSequence implementations, and that would not collide with the equals() already in use by String... so we got CharSequence.contentEquals(), which is inherited by String.

If CharSequence has been present in Java 1.0, we would probalby have only CharSequence.equals() and String would simply implement that.

Ah, the joys of evolving languages...

0

精彩评论

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