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


Відповіді:


171

Він String#equals()не тільки порівнює вміст String, але і перевіряє, чи є інший об'єкт також екземпляром a String. String#contentEquals()Тільки порівнює вміст (послідовність символів) і не НЕ перевірити , якщо інший об'єкт також є екземпляром String. Це може бути що завгодно , до тих пір , як це реалізація CharSequenceяких охоплює ат String, StringBuilder, StringBuffer, CharBufferі т.д.


12
Отже, чи схожі на оператори ==(contentEquals) та ===(equals) в JavaScript?
anestv

2
@anestv На Java ==оператор дозволить лише порівнювати посилання, а не зміст двох об'єктів.
Стефан

2
@ Алекс для уточнення, оператор == на Java призначений для перевірки того, чи два об'єкти вказують на одне місце в пам'яті або два рівні примітивів (байт, короткий, int, довгий, float, double, char, boolean) рівні.
La-comadreja

2
@Stephan, ==згаданий лише 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. Усі інші типи об'єктів вважаються не рівними.

  • String.contentEquals()можна порівняти StringBufferі StringBuilderінтелектуально. Він не викликає важкого toString()методу, який копіює весь вміст у новий об'єкт String. Натомість він порівнює з базовим char[]масивом, що чудово.


31

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

Якщо ви подивитеся на вихідний код, рядок # дорівнює та 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містить будь- stringякий, який має три символи

        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

4
@dbw ця відповідь - з відповіді, яку ви опублікували
Prateek

@dbw Крім того, чому ви все одно видалили свою публікацію?
MC Імператор

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()поверне помилковим, оскільки еквівалентно () перевіряє для instanceOf ( if (anObject instance of String)), який повертає помилкове, якщо аргумент є 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;
 }

Існує ще один метод рядка # 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

7

String # equals приймає Object як аргумент і перевіряє, чи це екземпляр String об'єкта чи ні. Якщо об'єктом аргументу є String Object, то він порівнює вміст символів за символами. Він повертає істину, якщо вміст обох рядкових об'єктів однаковий.

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

У contentEquals () довжина порівнюється перед будь-якою перевіркою екземпляра об'єкта. Якщо довжина однакова, він перевіряє об'єкт аргументу - це примірник AbstractStringBuilder чи ні. Якщо це так (тобто StringBuffer або StringBuilder), то вміст перевіряється символом за символом. У випадку, якщо аргумент є екземпляром об'єкта String, тоді String # дорівнює виклику з String # contentEquals.

Отже, коротше,

Рядок # дорівнює порівнянні символу вмісту за символом, якщо аргументом також є об'єкт String. І String # contentEquals порівнює вміст у випадку, якщо об’єкт аргументу реалізує інтерфейс CharSequence.

String # contentEquals проходить повільніше, якщо ми порівнюємо два рядкових контенту однакової довжини, як String # contentEquals, внутрішньо викликає String # рівний для String об'єкта.

У випадку, якщо ми спробуємо порівняти об'єкти з різницею довжини вмісту (скажімо, "abc" з "abcd"), то String # contentEquals швидше, ніж String # дорівнює. Тому що довжина порівнюється перед будь-якою перевіркою екземпляра об'єкта.


6

У contentEquals()перевіряє метод є зміст же між а String, StringBufferі т.д. , які яке - то послідовність напівкоксу.


5

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

Якщо CharSequence був присутній у Java 1.0, ми б заборонили мати лише CharSequence.equals (), а String це просто реалізував би.

Ах, радощі мов, що розвиваються ...

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.