assertEqualsвикористовує equalsметод для порівняння. Існує інше твердження assertSame, яке використовує ==оператор.
Щоб зрозуміти, чому ==не слід використовувати рядки, потрібно зрозуміти, що ==робить: це перевірка ідентичності. Тобто a == bперевіряє, чи є aта чи bпосилається на той самий об’єкт . Він вбудований у мову, і його поведінку не може бути змінено різними класами. equalsМетод, з іншого боку, можуть бути перекриті класами. Хоча поведінка за замовчуванням (у Objectкласі) полягає у тому, щоб перевірити ідентичність за допомогою ==оператора, багато класів, у тому числі String, переосмислюють її, а не перевіряють "еквівалентність". У випадку Stringзамість того , щоб перевіряти, чи є aта bпосилається на той самий об’єкт,a.equals(b) перевіряє, чи є об'єкти, на які вони посилаються, обидва рядки, що містять абсолютно однакові символи.
Час аналогії: уявіть, що кожен Stringпредмет - це аркуш паперу з чимось написаним на ньому. Скажімо, у мене два аркуші паперу з написом "Foo", а на іншому - "Bar". Якщо я візьму перші два аркуші паперу і використаю ==для їх порівняння, він повернеться, falseоскільки по суті запитає: "це той самий папірець?". Не потрібно навіть дивитися на те, що написано на папері. Те, що я даю їй два папірці (а не той самий два рази), означає, що воно повернеться false. Якщо я використовую equals, проте equalsметод прочитає два аркуші паперу і побачить, що вони говорять те саме ("Foo"), і тому він повернеться true.
Біт, який заплутається у Strings, полягає в тому, що Java має концепцію "інтернування" Strings, і це (ефективно) автоматично виконується на будь-яких рядкових літералах вашого коду. Це означає, що якщо у вашому коді є два еквівалентні рядкові літерали (навіть якщо вони є в різних класах), вони насправді обидва посилаються на один і той же Stringоб’єкт. Це змушує ==оператора повертатися trueчастіше, ніж можна було очікувати.