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
.
Проблема, которая путает со строками, заключается в том, что в Java есть концепция «интернирования» строк, и это (эффективно) автоматически выполняется для любых строковых литералов в вашем коде. Это означает, что если в вашем коде есть два эквивалентных строковых литерала (даже если они находятся в разных классах), они на самом деле оба ссылаются на один и тот же String
объект. Это заставляет ==
оператора возвращаться true
чаще, чем можно было ожидать.