Я создаю мини-игру, в которой пользователь пытается угадать имя. Но когда я хочу сравнить две текстовые строки, чтобы увидеть, одинаковы ли они, это, похоже, не работает.
final String miNombre = "Jordi";
Scanner input = new Scanner(System.in);
System.out.println("Adivina mi nombre: ");
while (true) {
String intento = input.next();
if(intento == miNombre) {
System.out.println("Acertaste!");
break;
} else {
System.out.println("Intentalo de nuevo!");
}
}
ВЫХОД:
Adivina mi nombre:
manuel
Intentalo de nuevo!
jordi
Intentalo de nuevo!
Jordi
Intentalo de nuevo!
Если
Java
только примитивные типы (описанные в JLS (§4.2) , напримерint
илиchar
) сравниваются с==
,String
s (и другие объекты) вJava
сравниваются друг с другом с помощью методаequals
.String#equals(Object)
==
для сравнения ссылок на типыString
, проверка на равенство определяет, ссылаются ли два операнда на один и тот же объектString
. В результатеfalse
операнды являются разными объектами String, даже если они содержат одинаковую последовательность символов.Таким образом, ваше сравнение должно быть:
ВЫХОД:
ПОЯСНЕНИЯ:
Я поместил переменную
miNombre
в начало сравнения, чтобы избежатьNullPointerException
ifintento == null
(да, сравнения сnull
также выполняются с помощью==
).В качестве дополнения: если это
null
действительное значение в представлении (и поэтому мы хотим избежать одногоNPE
), оноObjects.equals
доступно изJava 7
и заботится о возврате true, если оба значения истинныnull
илиfalse
если только одно истинно.В этом случае вы можете использовать метод
String#equalsIgnoreCase(Object)
, который будет игнорироватьMAYUSCULAS
илиMINUSCULAS
при выполнении сравнения:JLS (§15.21) Операторы равенства (
==
и!=
) можно использовать для сравнения двух операндов, которые могут быть преобразованы (§5.1.8) числового типа, или двух операндов типаboolean
или ,Boolean
или двух операндов, которые>
имеют тип ссылки, или типnull
. Все остальные случаи вызывают ошибку времени компиляции.Начиная с Java 7 можно сравнивать равенство двух строк , используя метод
equals
классаjava.util.Objects
. То есть:Так как они могут
a.equals(b)
либоb.equals(a)
колдоватьjava.lang.NullPointerException
если онa
илиnull
онb
соответственноnull
, при использовании этого пути,a
либоb
они могут бытьnull
без всякого риска.Если вы используете Java 6 (или более раннюю версию), код этого класса можно переписать
if
следующим образом:Оператор "==" сравнивает две ссылки, то есть возвращает true , если оба объекта занимают одну и ту же ячейку памяти.
Метод «равно» сравнивает значения объектов.
Это распространенная ошибка начинающих разработчиков.
Чтобы дополнить другие ответы, я скажу вам, что нет правила для сравнения равенства строки, и метод,
.equals()
и оператор == полностью действительны, разница зависит от того, что вы хотите сравнить или каково ваше намерение, когда вы хотите сравнить два объектаString
(по ссылке или по значению).Строки — это такие же объекты, как и любые другие, но есть большие и тонкие отличия, которые отделяют их от остальных объектов. Прежде всего, вы можете инициализировать строку двумя этими способами.
В обоих случаях создается объект, отсутствие оператора
new
в первом примере — это просто ярлык (так выглядит более естественно).Теперь вы должны понять, как Java управляет строками, в Java есть пул строк, это пространство памяти, зарезервированное для хранения строк, приложение обычно интенсивно использует строки, и только они могут занимать до 40% памяти во время выполнения. и многие из этих строк повторяются, например, «a», «en», «la» и т. д. Чтобы оптимизировать это, Java собирает все эти строки как литералы в местоположении JVM и повторно использует повторяющиеся литералы для оптимизации использования памяти, поэтому, если вы сохраните литерал «carlos» в двух переменных, Java будет повторно использовать этот литерал.
По этой причине, если вы объявите следующие переменные
String
и инициализируете их одним и тем же литералом. (помните, что вы создаете два объекта)Сравнение с оператором == вернет true, потому что пул строк повторно использует литерал "carlos" и, следовательно, они являются одной и той же ссылкой, поэтому сравнение вполне допустимо.
Пул строк перерабатывает и хранит только литералы, это означает, что если вы создадите строку следующим образом
Поскольку он не инициализируется литералом Java, он не будет храниться в пуле строк и не будет перерабатываться, поэтому он будет удален сборщиком мусора, если это так, то следующее сравнение приведет к ложному результату.
Вот почему, когда вы выполняете сравнение с оператором ==, он иногда возвращает true, а иногда false, даже если вы сравниваете одно и то же значение в строке.
Метод .equals используется, когда вы хотите сравнить строку по значению или символ за символом, это безопасный способ сделать сравнение строк, поскольку помните, что, как и в первом примере, мы технически делали сравнение по значению с оператором == из-за особенности пула строк.
Дополнительное примечание, если вам интересно, если при инициализации строки литералом значение сохраняется в пуле строк, что происходит, когда я изменяю строку?
Ну, это еще один момент, строки в Java неизменяемы, это означает, что вы не можете изменить их значение, например, добавить больше символов в значение String, а Java не предоставляет никакого API для прямого изменения строки. (однако Java предоставляет API, чтобы сделать это косвенно)
Например, если я хочу добавить фамилию в свою переменную (имя), я могу повторно назначить новую строку переменной (имени), которую я создам путем объединения исходного значения с фамилией в Сюда.
Это создает новое значение "carlos lucero" и присваивает это значение строке имени.
Что произойдет, если теперь я сравню «имя» с новой переменной, которая содержит то же значение, что и «имя», но назначена как литерал?
Ну, так как переменной (имя) было переназначено новое значение, которое не было создано с помощью литерала , теперь переменной (имя) больше нет в пуле строк, поэтому ее ссылка не перерабатывается и сравнение с переменная (FullName), которая, если она была создана с помощью литерала, в результате даст False.
Наконец, Java предоставляет API для решения проблемы неизменности строк, этот API предоставляется классом
StringBuilder
.Как уже было сказано, оператор == подтверждает в случае примитивов, что значения идентичны, в случае объектов ссылка указывает на один и тот же объект.
Осталось немного объяснить метод equals() . Все классы в Java являются подклассами Object , объект поставляется с объявлением equals() по умолчанию .
Если я объявлю новый класс, другие пользователи моего класса ожидают, что я реализую метод equals(Object o) , который подразумевает, что два объекта считаются равными. Это не обязательно означает, что они есть, и могут потребовать комментариев в документации. Пример:
Если я объявлю подкласс Point с меткой вроде:
Я должен отметить, что две NamedPoints считаются равными, если координаты совпадают, независимо от метки.
Осторожно, простое переопределение метода не гарантирует согласованности моей логики. Если я переопределю equals в NamedPoint , чтобы также учитывать метки, у меня останется следующая проблема:
Чтобы избежать этой двусмысленности, вы можете сравнить классы вместо использования instanceof:
Описание: В вопросе равенства есть драконы.
Оператор == обычно работает, когда переменная уже инициализирована, так как он сравнивает внутренние представления, но самый правильный метод — это сравнение с использованием метода equals, который унаследован от класса
Object
.Сравнение их с использованием равных почти всегда является лучшим решением.
Но, несмотря на это, у вас могут возникнуть проблемы, если ваша виртуальная машина меньше, чем Tiger, потому что в неудачных реализациях строка, определенная как
null
, не совпадала с пустой строкой.Поэтому для этих случаев вы можете использовать сравнение с помощью оператора
==
Или имея большой резерв, сравнивая внутренние представления.
"==" используется для Integer , Char, Object или null, среди прочего, лучше использовать equals или equalsIgnoreCase:
Только для примитивных типов сравнение == вообще допустимо. Для объектов следует использовать методы сравнения, так как
equals()
это может быть справедливо дляStrings
. Для других типов объектов этот тип сравнения может оказаться недопустимым.При == сравниваются ссылки, а не содержимое объектов в памяти.
Правильный способ сравнить 2 строки — использовать функцию equals() , которая предназначена для сравнения 2 строк и equalsIngnoreCase() , которая является той же самой, но игнорирует регистр.
Тест: