Разница между методами String # equals и String # contentEquals

Ответы:

171

Он String#equals()не только сравнивает содержимое строки, но также проверяет, является ли другой объект также экземпляром String. String#contentEquals()Только сравнивает содержимое (последовательность символов) и не не проверить , если другой объект также является экземпляром String. Это может быть что угодно , до тех пор , как это реализация CharSequenceкоторых охватывает ао String, StringBuilder, StringBuffer, CharBufferи т.д.

BalusC
источник
12
Итак, это как операторы ==(contentEquals) и ===(равно) в JavaScript?
anestv
2
@anestv В Java ==оператор разрешает сравнивать только ссылки, а не содержимое двух объектов.
Стефан
2
@ Чтобы уточнить, оператор == в Java предназначен для проверки того, указывают ли два объекта на одно и то же место в памяти или же два примитивных типа (byte, short, int, long, float, double, char, boolean) равны.
La-comadreja
2
@ Стефан, ==упомянутый только JavaScript; это никогда не упоминается в отношении Java.
Олат
@anestv, есть различия ( ==в JavaScript гораздо слабее, чем contentEquals, например, не будет касаться цифр), но вы правильно equalsпроверяете точное совпадение типов сStrings (другие классы могут быть слабее с типами в их equalsметодах) ,
Олат
43

Проще говоря: String.contentEquals()это умный брат String.equals(), потому что он может быть более свободным в реализации, чем String.equals().

Есть несколько причин, почему существует отдельный String.contentEquals()метод. Самая важная причина, я думаю, это:

  • equalsМетод должен быть рефлексивными. Это означает , что: x.equals(y) == y.equals(x). Это подразумевает, что aString.equals(aStringBuffer)должно быть так же, как aStringBuffer.equals(aString). Это потребует от разработчиков Java API создания специальной реализации для Strings в equals()методах StringBuffer, StringBuilder и CharSequence. Это было бы беспорядок.

Это где String.contentEqualsприходит. Это метод автономного , который никак не должен следовать строгим требованиям и правилам для Object.equals. Таким образом, вы можете более свободно реализовать смысл «равного содержания» . Это позволяет вам делать интеллектуальные сравнения, например, между StringBuffer и String.

И сказать, в чем именно разница:

  • String.contentEquals()может сравнить содержимое a String, a StringBuilder, a StringBuffer, a CharSequenceи всех производных классов из них. Если параметр имеет тип String, то String.equals()выполняется.

  • String.equals()сравнивает только строковые объекты. Все остальные типы объектов считаются не равными.

  • String.contentEquals()Можно сравнить StringBufferи StringBuilderпо-умному. Он не вызывает тяжелый toString()метод, который копирует весь контент в новый объект String. Вместо этого он сравнивается с базовым char[]массивом, и это здорово.

Мартейн Курто
источник
31

Этот ответ уже был опубликован dbw, но он удалил его, но у него были очень веские баллы для разницы при сравнении времени выполнения, какие исключения выбрасываются,

Если вы посмотрите на исходный код String # equals и String # contentEquals, становится ясно, что есть два переопределенных метода, String#contentEqualsодин из которых принимает, StringBuilderа другой - нет CharSequence.
Разница между ними,

  1. String#contentEqualsскинет NPE, если заданный аргумент есть, nullно String#equalsвернетfalse
  2. String#equalsсравнивает содержимое только в том instance of Stringслучае, если задан аргумент, иначе он вернется falseво всех других случаях, но с другой стороны String#contentEqualsпроверяет содержимое всех объектов, которые реализуют интерфейс CharSequence.
  3. Вы также можете настроить код так, чтобы он String#contentEqualsвозвращал неправильный результат или результат, который вы хотите, переопределив equalsметод аргумента, переданного, как показано ниже, но вы не можете сделать эти изменения с String#equals.
    Приведенный ниже код всегда будет отображатьсяtrue до тех пор, пока он sсодержит string3 символа.

        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будет медленнее, чем String#Equalsв случае, если предоставленный аргумент равен, instance of Stringа длина обоих Stringодинакова, но содержимое не равно.
    Пример, если строка есть String s = "madam"и String argPassed = "madan"затем s.contentEquals(argPassed)в этом случае займет почти вдвое больше времени по сравнению сs.equals(argPassed)

  5. Если длина содержимого не одинакова для обеих строк, тогда функция String#contentEqualsбудет иметь лучшую производительность, чем String#Equalsпочти во всех возможных случаях.

Еще один момент, чтобы добавить к его ответу

  1. String#contentEqualsиз Stringобъекта также будет сравнить с StringBuilderсодержанием и обеспечить соответствующий результат то время как String#EqualsВЕРНЕТСЯfalse
Prateek
источник
4
@dbw этот ответ взят из вашего ответа
Prateek
@dbw Кроме того, почему ты вообще удалил свой пост?
MC Emperor
14
  • Stringequals(Object o)метод класса делает только Stringсравнение. Но contentEquals(CharSequence cs)проверка на классы распространяется AbstractStringBuilderИЭ StringBuffer, StringBuilderи Stringкласс также (все они имеют тип CharSequence).

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

вывод:

false
true

Выход первого зЬтЬ это falseпотому , что builderне относится к типу Stringтак equals()возвращается , falseно на contentEquals()проверку на содержание всех типов , как StringBuilder, StringBuffer, Stringи , как содержание такой же поэтому true.

  • contentEqualsсгенерирует, NullPointerExceptionесли задан аргумент, nullно equals()вернет false, потому что equals () проверяет instanceOf ( if (anObject instance of String)), который возвращает false, если аргумент равен null.
Попытка
источник
14

contentEquals(CharSequence cs):

  • Позволяет проверить равенство заданного значения строки с помощью любого экземпляра реализации интерфейса java.lang.CharacterSequence(например, CharBuffer, Segment, String, StringBuffer, StringBuilder)

equals(Object anObject):

  • Позволяет проверить равенство заданного значения строки с помощью любого экземпляра типа java.lang.String только

RTFC :)

Поскольку чтение исходного кода - лучший способ понять его, я делюсь реализацией обоих методов (по состоянию на 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;
 }

Есть еще один метод String # contentEquals ():

public boolean contentEquals(StringBuffer sb) {
    synchronized(sb) {
        return contentEquals((CharSequence)sb);
    }
}
Амит Шарма
источник
9

equals()и contentEquals()два метода в Stringклассе, чтобы сравнить два stringsи stringс StringBuffer.

Параметры contentEquals()есть StringBufferи String(charSequence). equals()используется для сравнения двух stringsи contentEquals()используется для сравнения содержимого Stringи StringBuffer.

Метод contentEqualsи equalsявляются

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

Вот код, который описывает оба метода

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);
    }
}

Вывод:

 str1.equals(str2) - true
 str1.equals(sb1) - false
 str1.contentEquals(sb1) - true
 str1.contentEquals(sb2) - false
 str1.contentEquals(str2) - true
Asfab
источник
7

String # equals принимает Object в качестве аргумента и проверяет, является ли он экземпляром объекта String или нет. Если аргументом является объект String, он сравнивает содержимое символ за символом. Возвращает true, если содержимое обоих строковых объектов одинаково.

String # contentEquals принимает интерфейс CharSequence в качестве аргумента. CharSequence может быть реализован двумя способами: с помощью i) класса String или (ii) AbstractStringBuilder (родительский класс StringBuffer, StringBuilder)

В contentEquals () длина сравнивается перед проверкой любого экземпляра объекта. Если длина одинакова, то проверяется, является ли объект аргумента экземпляром AbstractStringBuilder или нет. Если это так (т.е. StringBuffer или StringBuilder), то содержимое проверяется посимвольно. Если аргумент является экземпляром объекта String, тогда String # equals вызывается из String # contentEquals.

Короче говоря,

String # equals сравнивает содержимое символ за символом в случае, если аргумент также является объектом String. And String # contentEquals сравнивает содержимое в случае, если объект аргумента реализует интерфейс CharSequence.

String # contentEquals работает медленнее, если мы сравниваем два строковых содержимого одинаковой длины, так как String # contentEquals внутренне вызывает String # equals для объекта String.

Если мы пытаемся сравнить объекты с разной длиной содержимого (скажем, «abc» с «abcd»), то String # contentEquals быстрее, чем String # равно. Потому что длина сравнивается перед проверкой экземпляра объекта.

Анирбан Пал
источник
6

В contentEquals()проверяет метод является содержание же между а String,StringBuffer и т.д. , которые какое - то последовательность полукокса.

fastcodejava
источник
5

Кстати, историческая причина разницы в том, что String изначально не имел суперкласса, поэтому String.equals () принимает String в качестве аргумента. Когда CharSequence был представлен в качестве суперкласса String, он нуждался в собственном тесте на равенство, который работал бы во всех реализациях CharSequence и который не вступал бы в конфликт с equals (), уже используемым String ... поэтому мы получили CharSequence.contentEquals ( ), который наследуется String.

Если бы CharSequence присутствовал в Java 1.0, мы, вероятно, имели бы только CharSequence.equals (), и String просто реализовал бы это.

Ах, радости развивающихся языков ...

keshlam
источник