Как мне сравнить строки в Java?
Я использую ==
оператор в моей программе, чтобы сравнить все мои строки до сих пор. Тем не менее, я столкнулся с ошибкой, изменил одну из них в .equals()
вместо этого, и это исправило ошибку.
Является ==
плохой? Когда это должно и не должно быть использовано? Какая разница?
23 ответа
==
тесты на равенство ссылок (являются ли они одним и тем же объектом).
.equals()
тесты на равенство значений (являются ли они логически "равными").
Objects.equals () проверяет наличие null
перед звонком .equals()
так что вам не нужно (доступно с JDK7, также доступно в Гуаве).
String.contentEquals () сравнивает содержимое String
с содержанием любого CharSequence
(доступно с версии Java 1.5).
Следовательно, если вы хотите проверить, имеют ли две строки одинаковое значение, вы, вероятно, захотите использовать Objects.equals()
,
// These two have the same value
new String("test").equals("test") // --> true
// ... but they are not the same object
new String("test") == "test" // --> false
// ... neither are these
new String("test") == new String("test") // --> false
// ... but these are because literals are interned by
// the compiler and thus refer to the same object
"test" == "test" // --> true
// ... string literals are concatenated by the compiler
// and the results are interned.
"test" == "te" + "st" // --> true
// ... but you should really just call Objects.equals()
Objects.equals("test", new String("test")) // --> true
Objects.equals(null, "test") // --> false
Objects.equals(null, null) // --> true
Вы почти всегда хотите использовать Objects.equals()
, В редкой ситуации, когда вы знаете, что имеете дело с интернированными строками, вы можете использовать ==
,
Из JLS 3.10.5. Строковые литералы:
Более того, строковый литерал всегда ссылается на один и тот же экземпляр класса.
String
, Это связано с тем, что строковые литералы - или, в более общем смысле, строки, являющиеся значениями константных выражений ( §15.28) - "интернированы", чтобы использовать уникальные экземпляры с использованием методаString.intern
,
Подобные примеры также можно найти в JLS 3.10.5-1.
==
проверяет ссылки на объекты, .equals()
проверяет строковые значения.
Иногда это выглядит так, как будто ==
сравнивает значения, потому что Java делает кое-что закулисное, чтобы убедиться, что идентичные строки в действительности являются одним и тем же объектом.
Например:
String fooString1 = new String("foo");
String fooString2 = new String("foo");
// Evaluates to false
fooString1 == fooString2;
// Evaluates to true
fooString1.equals(fooString2);
// Evaluates to true, because Java uses the same object
"bar" == "bar";
Но остерегайтесь нулей!
==
ручки null
струны в порядке, но звонит .equals()
из пустой строки вызовет исключение:
String nullString1 = null;
String nullString2 = null;
// Evaluates to true
System.out.print(nullString1 == nullString2);
// Throws a NullPointerException
System.out.print(nullString1.equals(nullString2));
Так что, если вы знаете, что fooString1
может быть нулевым, скажите читателю, что написав
System.out.print(fooString1 != null && fooString1.equals("bar"));
Ниже короче, но менее очевидно, что он проверяет на ноль (из Java 7):
System.out.print(Objects.equals(fooString1, "bar"));
==
сравнивает ссылки на объекты
.equals()
сравнивает строковые значения
Иногда ==
дает иллюзии сравнения значений String, как в следующих случаях:
String a="Test";
String b="Test";
if(a==b) ===> true
Это связано с тем, что когда вы создаете какой-либо литерал String, JVM сначала ищет этот литерал в пуле String, и, если он найдет совпадение, эта же ссылка будет передана новой строке. Из-за этого мы получаем:
(a == b) ===> верно
String Pool
b -----------------> "test" <-----------------a
Тем не мение, ==
терпит неудачу в следующем случае:
String a="test";
String b=new String("test");
if (a==b) ===> false
В этом случае для new String("test")
оператор новой строки будет создан в куче, и эта ссылка будет дана b
, так b
будет дана ссылка на кучу, а не в пул строк.
Сейчас a
указывает на строку в пуле строк, в то время как b
указывает на строку в куче. Из-за этого мы получаем:
если (a==b) ===> false.
String Pool
"test" <-------------------- a
Heap
"test" <-------------------- b
В то время как .equals()
всегда сравнивает значение String, поэтому оно дает true в обоих случаях:
String a="Test";
String b="Test";
if(a.equals(b)) ===> true
String a="test";
String b=new String("test");
if(a.equals(b)) ===> true
Итак, используя .equals()
всегда лучше
==
Оператор проверяет, являются ли две строки одним и тем же объектом.
.equals()
Метод проверит, имеют ли две строки одинаковое значение.
Строки в Java неизменны. Это означает, что всякий раз, когда вы пытаетесь изменить / модифицировать строку, вы получаете новый экземпляр. Вы не можете изменить исходную строку. Это было сделано для кэширования этих экземпляров строк. Типичная программа содержит много строковых ссылок, и кэширование этих экземпляров может уменьшить объем используемой памяти и повысить производительность программы.
При использовании оператора == для сравнения строк вы не сравниваете содержимое строки, а фактически сравниваете адрес памяти. Если они оба равны, он вернет true и false в противном случае. Принимая во внимание, что равно в строке сравнивает содержимое строки.
Таким образом, вопрос в том, все ли строки кэшированы в системе, почему ==
возвращает ложь, тогда как равны возвращают истину Ну, это возможно. Если вы делаете новую строку, как String str = new String("Testing")
Вы заканчиваете тем, что создали новую строку в кеше, даже если кеш уже содержит строку с таким же содержимым. Короче "MyString" == new String("MyString")
всегда будет возвращать false.
Java также говорит о функции intern(), которая может использоваться в строке, чтобы сделать ее частью кэша, так "MyString" == new String("MyString").intern()
вернет истину.
Примечание: оператор == намного быстрее, чем равен, просто потому, что вы сравниваете два адреса памяти, но вы должны быть уверены, что код не создает новые экземпляры String в коде. В противном случае вы столкнетесь с ошибками.
String a = new String("foo");
String b = new String("foo");
System.out.println(a == b); // prints false
System.out.println(a.equals(b)); // prints true
Убедитесь, что вы понимаете, почему. Это потому что ==
сравнение только сравнивает ссылки; equals()
Метод выполняет посимвольное сравнение содержимого.
Когда вы звоните новый для a
а также b
каждый получает новую ссылку, которая указывает на "foo"
в таблице строк. Ссылки разные, но содержание одинаковое.
Да, это плохо...
==
означает, что ваши две строковые ссылки - это один и тот же объект. Возможно, вы слышали, что это так, потому что Java хранит своего рода буквальную таблицу (что она делает), но это не всегда так. Некоторые строки загружаются по-разному, создаются из других строк и т. Д., Поэтому вы никогда не должны предполагать, что две одинаковые строки хранятся в одном месте.
Равный делает реальное сравнение для вас.
Да, ==
плохо для сравнения строк (любые объекты на самом деле, если вы не знаете, что они канонические). ==
просто сравнивает ссылки на объекты. .equals()
тесты на равенство. Для строк часто они будут одинаковыми, но, как вы обнаружили, это не гарантируется всегда.
У Java есть пул String, в котором Java управляет выделением памяти для объектов String. Посмотрите Струнные Бассейны на Яве
Когда вы проверяете (сравниваете) два объекта, используя ==
Оператор сравнивает равенство адресов в пуле строк. Если два объекта String имеют одинаковые адреса адресов, он возвращает true
, иначе false
, Но если вы хотите сравнить содержимое двух объектов String, вы должны переопределить equals
метод.
equals
фактически является методом класса Object, но он переопределяется в класс String, и дается новое определение, которое сравнивает содержимое объекта.
Example:
stringObjectOne.equals(stringObjectTwo);
Но учтите, что это относится к делу String. Если вы хотите сравнить без учета регистра, вы должны перейти к методу equalsIgnoreCase класса String.
Посмотрим:
String one = "HELLO";
String two = "HELLO";
String three = new String("HELLO");
String four = "hello";
one == two; // TRUE
one == three; // FALSE
one == four; // FALSE
one.equals(two); // TRUE
one.equals(three); // TRUE
one.equals(four); // FALSE
one.equalsIgnoreCase(four); // TRUE
Я согласен с ответом от zacherates.
Но то, что вы можете сделать, это позвонить intern()
на ваших не буквальных строках.
Из примера zacherates:
// ... but they are not the same object
new String("test") == "test" ==> false
Если вы интернировать не буквальное равенство строк true
new String("test").intern() == "test" ==> true
==
сравнивает ссылки на объекты в Java, и это не исключение для String
объекты.
Для сравнения фактического содержания объектов (в том числе String
), нужно использовать equals
метод.
Если сравнение двух String
объекты, использующие ==
оказывается true
это потому что String
объекты были интернированы, и виртуальная машина Java имеет несколько ссылок, указывающих на один и тот же экземпляр String
, Не следует ожидать, что сравнение одного String
объект, содержащий то же содержимое, что и другой String
использование объекта ==
оценивать как true
,
.equals()
сравнивает данные в классе (при условии, что функция реализована). ==
сравнивает местоположение указателя (расположение объекта в памяти).
==
возвращает значение true, если оба объекта (НЕ ОБРАЩАЯСЯ О ПРИМИТИВАХ) указывают на тот же экземпляр объекта. .equals()
возвращает true, если два объекта содержат одинаковые данные equals()
Против ==
на Яве
Это может помочь вам.
==
выполняет проверку равенства ссылок, ссылаются ли 2 объекта (в данном случае строки) на один и тот же объект в памяти.
equals()
Метод проверит, являются ли содержимое или состояния двух объектов одинаковыми.
очевидно ==
быстрее, но будет (может) давать ложные результаты во многих случаях, если вы просто хотите сказать, если 2 String
s содержат тот же текст.
Определенно использование equals()
метод рекомендуется.
Не беспокойтесь о производительности. Некоторые вещи, чтобы поощрить использование String.equals()
:
- Реализация
String.equals()
Первые проверки на равенство ссылок (используя==
), и если 2 строки одинаковы для справки, дальнейшие вычисления не выполняются! - Если 2 строковые ссылки не совпадают,
String.equals()
Далее проверим длины строк. Это также быстрая операция, потому чтоString
Класс хранит длину строки, не нужно подсчитывать символы или кодовые точки. Если длины различаются, дальнейшая проверка не выполняется, мы знаем, что они не могут быть равны. - Только если мы дошли до этого уровня, содержимое 2 строк будет фактически сопоставлено, и это будет кратким сравнением: не все символы будут сравниваться, если мы обнаружим несовпадающий символ (в той же позиции в 2 строках), дальнейшие символы проверяться не будут.
Когда все сказано и сделано, даже если у нас есть гарантии, что строки являются интернами, используя equals()
Метод по-прежнему не так уж и сложен, как можно подумать, определенно рекомендуемый способ. Если вам нужна эффективная проверка ссылок, используйте перечисления, если в спецификации и реализации языка гарантируется, что одно и то же значение перечисления будет одним и тем же объектом (посредством ссылки).
Если вы похожи на меня, когда я впервые начал использовать Java, я хотел использовать оператор "==", чтобы проверить, равны ли два экземпляра String, но, что бы там ни было, это неправильный способ сделать это в Java.
В этом уроке я продемонстрирую несколько разных способов правильного сравнения строк Java, начиная с подхода, который я использую большую часть времени. В конце этого руководства по сравнению строк Java я также расскажу, почему оператор "==" не работает при сравнении строк Java.
Вариант 1. Сравнение строк Java с помощью метода equals В большинстве случаев (возможно, в 95% случаев) я сравниваю строки с методом equals класса Java String, например:
if (string1.equals(string2))
Этот метод String equals просматривает две строки Java, и если они содержат одинаковую строку символов, они считаются равными.
Взглянув на пример быстрого сравнения строк с помощью метода equals, если бы был выполнен следующий тест, две строки не были бы признаны равными, потому что символы не совпадают (случай символов отличается):
String string1 = "foo";
String string2 = "FOO";
if (string1.equals(string2))
{
// this line will not print because the
// java string equals method returns false:
System.out.println("The two strings are the same.")
}
Но когда две строки содержат одинаковую строку символов, метод equals вернет true, как в этом примере:
String string1 = "foo";
String string2 = "foo";
// test for equality with the java string equals method
if (string1.equals(string2))
{
// this line WILL print
System.out.println("The two strings are the same.")
}
Вариант 2. Сравнение строк с помощью метода equalsIgnoreCase
В некоторых тестах сравнения строк вы захотите игнорировать, являются ли строки прописными или строчными. Если вы хотите проверить строки на равенство в этом случае без учета регистра, используйте метод equalsIgnoreCase класса String, например:
String string1 = "foo";
String string2 = "FOO";
// java string compare while ignoring case
if (string1.equalsIgnoreCase(string2))
{
// this line WILL print
System.out.println("Ignoring case, the two strings are the same.")
}
Вариант 3: сравнение строк Java с помощью метода CompareTo
Существует также третий, менее распространенный способ сравнения строк Java, это метод класса String compareTo. Если две строки в точности совпадают, метод compareTo вернет значение 0 (ноль). Вот быстрый пример того, как выглядит этот подход сравнения строк:
String string1 = "foo bar";
String string2 = "foo bar";
// java string compare example
if (string1.compareTo(string2) == 0)
{
// this line WILL print
System.out.println("The two strings are the same.")
}
Хотя я пишу об этой концепции равенства в Java, важно отметить, что язык Java включает метод equals в базовый класс Java Object. Всякий раз, когда вы создаете свои собственные объекты и хотите предоставить средство, чтобы увидеть, равны ли два экземпляра вашего объекта, вы должны переопределить (и реализовать) этот метод equals в вашем классе (так же, как язык Java обеспечивает это равенство / поведение сравнения в методе String equals).
Возможно, вы захотите взглянуть на это ==, .equals(), compareTo() и сравнить ()
==
оператор проверяет, указывают ли две ссылки на один и тот же объект или нет. .equals()
проверить фактическое содержимое строки (значение).
Обратите внимание, что .equals()
метод принадлежит классу Object
(супер класс всех классов). Вам необходимо переопределить его в соответствии с требованиями вашего класса, но для String он уже реализован, и он проверяет, имеют ли две строки одинаковое значение или нет.
Случай 1
String s1 = "Stack Overflow"; String s2 = "Stack Overflow"; s1 == s2; //true s1.equals(s2); //true
Причина: строковые литералы, созданные без нуля, хранятся в пуле строк в области permgen кучи. Таким образом, s1 и s2 указывают на один и тот же объект в пуле.
Дело 2
String s1 = new String("Stack Overflow"); String s2 = new String("Stack Overflow"); s1 == s2; //false s1.equals(s2); //true
Причина: если вы создаете объект String, используя
new
Ключевое слово отдельное пространство выделяется для него в куче.
Функция:
public float simpleSimilarity(String u, String v) {
String[] a = u.split(" ");
String[] b = v.split(" ");
long correct = 0;
int minLen = Math.min(a.length, b.length);
for (int i = 0; i < minLen; i++) {
String aa = a[i];
String bb = b[i];
int minWordLength = Math.min(aa.length(), bb.length());
for (int j = 0; j < minWordLength; j++) {
if (aa.charAt(j) == bb.charAt(j)) {
correct++;
}
}
}
return (float) (((double) correct) / Math.max(u.length(), v.length()));
}
Тестовое задание:
String a = "This is the first string.";
String b = "this is not 1st string!";
// for exact string comparison, use .equals
boolean exact = a.equals(b);
// For similarity check, there are libraries for this
// Here I'll try a simple example I wrote
float similarity = simple_similarity(a,b);
==
сравнивает эталонное значение объектов, тогда как equals()
метод присутствует в java.lang.String
класс сравнивает содержимое String
объект (для другого объекта).
Я думаю, что когда вы определяете String
Вы определяете объект. Так что вам нужно использовать .equals()
, Когда вы используете примитивные типы данных, которые вы используете ==
но с String
(и любой объект) вы должны использовать .equals()
,
Если equals()
метод присутствует в java.lang.Object
класс, и ожидается, что для проверки эквивалентности состояния объектов! Это означает, что содержимое объектов. Тогда как ==
Ожидается, что оператор будет проверять фактические экземпляры объекта одинаковы или нет.
пример
Рассмотрим две разные ссылочные переменные, str1
а также str2
:
str1 = new String("abc");
str2 = new String("abc");
Если вы используете equals()
System.out.println((str1.equals(str2))?"TRUE":"FALSE");
Вы получите вывод как TRUE
если вы используете ==
,
System.out.println((str1==str2) ? "TRUE" : "FALSE");
Теперь вы получите FALSE
в качестве выхода, потому что оба str1
а также str2
указывают на два разных объекта, хотя оба они имеют одинаковое строковое содержимое. Это из-за new String()
новый объект создается каждый раз.
Оператор == всегда предназначен для сравнения ссылок на объекты, тогда как метод класса String .equals() переопределяется для сравнения содержимого:
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1 == s2); // It prints false (reference comparison)
System.out.println(s1.equals(s2)); // It prints true (content comparison)
Все объекты гарантированно имеют .equals()
метод, так как объект содержит метод, .equals()
, который возвращает логическое значение. Задача подкласса - переопределить этот метод, если требуется дополнительное определение. Без него (т.е. используя ==
) только адреса памяти проверяются между двумя объектами на равенство. Строка переопределяет это .equals()
метод и вместо использования адреса памяти возвращает сравнение строк на уровне символов для равенства.
Ключевым моментом является то, что строки хранятся в одном единственном пуле, поэтому после создания строки она всегда сохраняется в программе по одному и тому же адресу. Строки не меняются, они неизменны. Вот почему плохая идея использовать обычную конкатенацию строк, если у вас есть серьезный объем обработки строк. Вместо этого вы бы использовали StringBuilder
классы предоставляются. Помните, что указатели на эту строку могут измениться, и если вам было интересно посмотреть, совпадают ли два указателя ==
было бы хорошим способом пойти. Сами струны нет.
В Java, когда оператор "==" используется для сравнения 2 объектов, он проверяет, ссылаются ли объекты на одно и то же место в памяти. Другими словами, он проверяет, являются ли два имени объекта в основном ссылками на одну и ту же ячейку памяти.
Класс Java String фактически переопределяет реализацию equals() по умолчанию в классе Object - и он переопределяет метод так, что он проверяет только значения строк, а не их расположение в памяти. Это означает, что если вы вызываете метод equals() для сравнения двух строковых объектов, то до тех пор, пока фактическая последовательность символов равна, оба объекта считаются равными.
==
Оператор проверяет, являются ли две строки одним и тем же объектом.
.equals()
Метод проверки, если две строки имеют одинаковое значение.
Вы также можете использовать compareTo()
метод для сравнения двух строк. Если результат CompareTo равен 0, тогда две строки равны, иначе сравниваемые строки не равны.
==
сравнивает ссылки и не сравнивает фактические строки. Если вы создали каждую строку, используя new String(somestring).intern()
тогда вы можете использовать ==
оператор для сравнения двух строк, в противном случае можно использовать только методы equals() или compareTo.