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
частіше, ніж можна було очікувати.