Подтвердить что ты не робот

Сравнение содержимого StringBuffer с равными

StringBuffer sb1 = new StringBuffer("Java");
StringBuffer sb2 = new StringBuffer("Java");
System.out.println(sb1 == sb2);
System.out.println(sb1.equals(sb2));

Здесь оба возвращаются false. Как это возможно?

4b9b3361

Ответ 1

Метод equals StringBuffer не переопределяется из Object, поэтому это просто ссылочное равенство, то есть то же, что и при использовании ==. Я подозреваю, что причина этого в том, что StringBuffer является изменяемым, а переопределение equals в основном полезно для классов, подобных значению, которые вы можете использовать в качестве ключей (хотя в списках также есть переопределенные equals и StringBuffer вид списка, так что это немного непоследовательно).

Ответ 2

Вы сравниваете ссылки на объекты StringBuffer, а не фактические строки в StringBuffer.

System.out.println(sb1.toString().equals(sb2.toString())) вернет true, и я предполагаю, что это то, чего вы ожидали или хотели достичь.

Ответ 3

Простой ответ заключается в том, что StringBufferStringBuilder) не переопределяют базовую семантику Object.equals(). Поэтому equals в StringBuffer будет просто сравнивать ссылки на объекты.

Фактически, String, StringBuffer, StringBuilder и CharBuffer все реализуют интерфейс CharSequence, и Javadoc для этого интерфейса говорит следующее:

Этот интерфейс не уточняет общие контракты методов equals и hashCode. Поэтому результат сравнения двух объектов, реализующих CharSequence, в общем случае не определен. Каждый объект может быть реализован отдельным классом, и нет никакой гарантии, что каждый класс сможет проверить свои экземпляры на равенство с экземплярами другого. Поэтому нецелесообразно использовать произвольные экземпляры CharSequence в качестве элементов в наборе или в качестве ключей на карте.

Также обратите внимание, что в Javadocs для StringBufferStringBuilder) прямо указано это:

API Note:

StringBuffer реализует Comparable, но не переопределяет equals. Таким образом, естественное упорядочение StringBuffer не согласуется с equals. Следует соблюдать осторожность, если объекты StringBuffer используются в качестве ключей в SortedMap или элементов в SortedSet.


Но почему?

В основе этого лежит тот факт, что String является неизменным, а StringBuffer/StringBuilder изменчивым.

  • Если два объекта String имеют одинаковые символы, они всегда будут иметь одинаковые символы. Поэтому естественно относиться к ним как к равным... и именно это String::equals(Object) делает.

  • Если два объекта StringBuffer могут иметь одинаковые символы сейчас, и разные символы через мгновение... из-за операции мутации, выполняемой другим потоком. Реализация equals(Object) для StringBuffer, которая чувствительна к (изменяющемуся) контенту, была бы проблематичной. Например:

    if (buf1.equals(buf2)) {
        // Do something to one of the StringBuffer objects.
    }
    

    имеет потенциальное состояние гонки. Другой пример - использование экземпляров StringBuffer в качестве ключей в HashTable или HashMap.

В любом случае, очень давно было принято преднамеренное проектное решение о том, что StringBuffer и StringBuilder не будут переопределять методы Object::equals и Object::hashCode.

Ответ 4

 1.  System.out.println(sb1 == sb2);  

Метод equals StringBuffer возвращает true только тогда, когда объект StringBuffer сравнивается с самим собой. Он возвращает false по сравнению с любым другим StringBuffer, даже если оба содержат одни и те же символы.

Это связано с тем, что "==" проверяет ссылочное равенство и поскольку оба sb1 и sb2 являются разными объектными ссылками, поэтому вывод в этом случае "false"

Тем не менее, если вы хотите проверить, равно ли содержимое в этих двух объектах StringBuffer, вы можете использовать это:

sb1.toString().equals(sb2.toString())

2. System.out.println(sb1.equals(sb2));

Это дает результат как "false", потому что метод .equals() не был переопределен в классе StringBuffer. Поэтому он использует метод .equals() из своего родительского класса Object. В классе объектов .equals() записано для проверки ссылочного равенства.

Обратите внимание, что sb3.equals(sb4) вернет "true" в случае String. Поскольку метод .equals() был переопределен в классе String, чтобы проверить и сопоставить содержимое двух разных строк.

Ответ 5

StringBuffer похоже, не имеет собственного метода equals, поэтому я предполагаю, что StringBuffer наследует метод equals Object, который сравнивается с помощью sb1 == sb2. Поэтому оба метода дают одинаковый результат.

Ответ 6

оба сравнивают две ссылки на объекты (sb1 - один, а sb2 - второй), поэтому оба они разные.

Если вы пытаетесь сравнить контент - используйте метод compareTo (...) в классе String - это - сначала получите Строка содержимое StringBuffer, используя метод toString() (.toString(). compareTo).

Ps. с JDK 5 существует еще один гораздо более быстрый класс, который ведет себя точно как StringBuffer - он StringBuilder , а также, но не является потокобезопасным.

StringBuffer sb1 = new StringBuffer("Java"); 
StringBuffer sb2 = new StringBuffer("Java"); 

System.out.println(sb1.toString().compareTo(sb2.toString())); 

Ответ 7

Интересно, почему StringBuffer не переопределяет метод equals. Вероятно, потому что содержимое объекта получается методом toString() и которое имеет желаемый метод.

Ответ 8

С JDK/11 теперь можно сравнивать два StringBuffer без дополнительного toString, это можно сделать с помощью недавно представленного API -

public int compareTo​(StringBuffer another)

Сравнивает два экземпляра StringBuffer лексикографически. Этот способ следует тем же правилам лексикографического сравнения, которые определены в метод CharSequence.compare(this, another). Подробное сравнение строк с учетом локали см. в разделе "Collator".

Замечание по реализации: этот метод синхронизируется с текущей объект, но не StringBuffer другой, с которым этот StringBuffer в сравнении.

Возвращает: значение 0, если этот StringBuffer содержит тот же символ последовательность как аргумент StringBuffer; отрицательное целое число, если этот StringBuffer лексикографически меньше, чем StringBuffer аргумент; или положительное целое число, если этот StringBuffer лексикографически больше, чем аргумент StringBuffer.

Пример использования:

StringBuffer stringBuffer = new StringBuffer("null");
StringBuffer anotherStringBuffer = new StringBuffer("NULL");
System.out.println(stringBuffer.compareTo(anotherStringBuffer) == 0); // shall print 'false'

Ответ 9

Stringbuffer equals() не переопределяется. Он не сравнивает значения, он только сравнивает назначения ссылочных значений. Вот почему вы становитесь ложным, поскольку оба они ссылаются на разные объекты.