Как сравнить строки в Java?

763

Я использовал оператор == в своей программе, чтобы сравнить все мои строки до сих пор. Однако я столкнулся с ошибкой, вместо этого изменил одну из них на .equals(), и исправил ошибку.

Является ли == плохим? Когда он должен и не должен использоваться? Какая разница?

  • 12
    Также полезно знать, что если вы переопределяете метод .equals (), убедитесь, что вы переопределяете метод .hashcode (), в противном случае вы получите нарушающее отношение эквивалентности ч / б equals и hashcode. Для получения дополнительной информации обратитесь к документу Java.
  • 0
    Оставив ссылку на мое объяснение, почему == работает так же, как и на объектах: stackoverflow.com/a/19966154/2284641
Показать ещё 2 комментария
Теги:
string
equality

23 ответа

5340
Лучший ответ

== тесты для ссылочного равенства (независимо от того, являются ли они одним и тем же объектом).

.equals() для равенства значений (независимо от того, являются ли они логически "равными").

Objects.equals() проверяет значение null перед вызовом .equals() поэтому вам не нужно (доступно с JDK7, также доступным в Guava).

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.

  • 340
    Я думаю, в Java вы должны сказать «ссылки» вместо «указатели».
  • 2
    Если вы можете делать вещи таким образом, то для чего полезен метод compareTo?
Показать ещё 49 комментариев
609

== проверяет ссылки на объекты, .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"));

Ниже короче, но его менее очевидно, что он проверяет значение null (из Java 7):

System.out.print(Objects.equals(fooString1, "bar"));
  • 83
    Иногда это выглядит , как если бы «==» сравнивает значения, - == вы всегда сравнивать значения! (Просто определенные значения являются ссылками!)
  • 5
    Увы, для isNullOrEmpty () нет статического метода и нет специальной перегрузки операторов, что делает эту часть Java более сложной, чем в C # или Python. А поскольку в Java нет методов расширения, вы не можете написать собственную утилиту для расширения java.lang.String. Правильно? Есть какие-нибудь мысли по поводу подкласса String, добавления этого статического служебного метода и последующего использования вместо него MyString? Статический метод с двумя параметрами для выполнения нулевых безопасных сравнений был бы неплохо иметь в этом подклассе.
Показать ещё 9 комментариев
425

== сравнивает ссылки на объекты.

.equals() сравнивает значения String.

Иногда == дает иллюзии сравнения значений String, как в следующих случаях:

String a="Test";
String b="Test";
if(a==b) ===> true

Это связано с тем, что при создании любого строкового литерала JVM сначала ищет этот литерал в пуле String, и если он находит совпадение, эта же ссылка будет передана новой String. Из-за этого получаем:

(a == b) === > true

                       String Pool
     b -----------------> "test" <-----------------a

Однако == не выполняется в следующем случае:

String a="test";
String b=new String("test");
if (a==b) ===> false

В этом случае для new String("test") оператор new String будет создан в куче, и эта ссылка будет указана на b, поэтому b будет дана ссылка на кучу, а не в String pool.

Теперь a указывает на String в пуле строк, а b указывает на String в куче. Из-за этого мы получаем:

if (a == b) === > false.

                String Pool
     "test" <-------------------- a

                   Heap
     "test" <-------------------- b

В то время как .equals() всегда сравнивает значение String, поэтому он дает истину в обоих случаях:

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() всегда лучше.

  • 3
    .equals () сравнивает два экземпляра, но для их сравнения используется метод equals. Это может сравнивать или не сравнивать вывод toString.
  • 3
    @Jacob Метод класса объекта .equals() сравнивает экземпляры (ссылки / адреса), где методы класса String .equals() переопределяются для сравнения содержимого (символов)
Показать ещё 1 комментарий
206

Оператор == проверяет, соответствуют ли две строки точно одному и тому же объекту.

Метод .equals() будет проверять, имеют ли две строки одинаковое значение.

  • 5
    Обычно я настоятельно рекомендую библиотеку Apache Commons: commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/… , java.lang.String).
  • 0
    Вы также можете использовать метод .compareTo (), если вы хотите оценить порядок строк.
165

Строки в Java неизменяемы. Это означает, что всякий раз, когда вы пытаетесь изменить/изменить строку, вы получаете новый экземпляр. Вы не можете изменить исходную строку. Это сделано для того, чтобы эти экземпляры строк могли кэшироваться. Типичная программа содержит множество ссылок на строки и кеширование этих экземпляров, что может уменьшить объем памяти и увеличить производительность программы.

При использовании оператора == для сравнения строк вы не сравниваете содержимое строки, а фактически сравниваете адрес памяти. Если они равны, в противном случае они вернут true и false. Если equals in string сравнивает содержимое строки.

Итак, вопрос в том, что все строки кэшируются в системе, как получилось, что == возвращает false, тогда как equals возвращает true? Ну, это возможно. Если вы создадите новую строку типа String str = new String("Testing"), вы создадите новую строку в кеше, даже если кэш уже содержит строку, содержащую тот же контент. Короче говоря, "MyString" == new String("MyString") всегда будет возвращать false.

Java также говорит о функции intern(), которая может использоваться в строке, чтобы сделать ее частью кеша, поэтому "MyString" == new String("MyString").intern() вернет true.

Примечание: == оператор намного быстрее, чем равен только потому, что вы сравниваете два адреса памяти, но вам нужно быть уверенным, что код не создает новые экземпляры String в коде. В противном случае вы столкнетесь с ошибками.

135
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() выполняет сопоставление содержимого по символам.

Когда вы вызываете new для a и b, каждый получает новую ссылку, которая указывает на "foo" в таблице строк. Ссылки разные, но контент один и тот же.

116

Да, это плохо...

== означает, что ваши две ссылки на строки - это точно один и тот же объект. Возможно, вы слышали, что это так, потому что Java хранит личную таблицу (что она делает), но это не всегда так. Некоторые строки загружаются по-разному, построены из других строк и т.д., Поэтому вы никогда не должны предполагать, что две одинаковые строки хранятся в одном месте.

Equals действительно для вас.

111

Java имеет пул строк, в котором Java управляет распределением памяти для объектов String. См. Строковые пулы в Java

Когда вы проверяете (сравниваете) два объекта с помощью оператора ==, он сравнивает равенство адресов в пуле строк. Если два объекта 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
  • 6
    Я вижу, что это поздний ответ на большой вопрос. Могу ли я спросить, что это дает, что еще не упомянуто в существующих ответах?
  • 6
    @Mysticial он добавил equalsIgnoreCase который может быть информативным для более equalsIgnoreCase .
111

Да, == плохо для сравнения строк (любые объекты действительно, если вы не знаете, что они канонические). == просто сравнивает ссылки на объекты. .equals() тесты для равенства. Для строк часто они будут такими же, как вы обнаружили, которые не гарантируются всегда.

97

.equals() сравнивает данные в классе (при условии, что функция реализована). == сравнивает местоположения указателя (расположение объекта в памяти).

== возвращает true, если оба объекта (NOT TALKING OF PRIMITIVES) указывают на экземпляр SAME. .equals() возвращает true, если два объекта содержат одни и те же данные equals() Versus == в Java

Это может вам помочь.

93

Я согласен с ответом от зачеловеков.

Но то, что вы можете сделать, это вызвать intern() для ваших нелиберальных строк.

Например, из примера zacherates:

// ... but they are not the same object
new String("test") == "test" ==> false 

Если вы ставите нелитеральное равенство строки, это true

new String("test").intern() == "test" ==> true 
  • 6
    Это вообще не очень хорошая идея. Стажировка относительно дорогая и может (как это ни парадоксально) >> увеличить << ваш объем памяти JVM и увеличить затраты на сборку мусора. В большинстве случаев они перевешивают преимущества производительности при использовании == для сравнения строк.
92

== выполняет проверку равенства reference, ссылаются ли 2 объекта (строки в этом случае) на один и тот же объект в памяти.

Метод equals() будет проверять, совпадают ли содержимое или состояния двух объектов.

Очевидно, что == быстрее, но во многих случаях может (может) дать ложные результаты, если вы просто хотите сказать, если 2 String содержит один и тот же текст.

Определенно рекомендуется использовать метод equals().

Не беспокойтесь о производительности. Некоторые способы поощрения использования String.equals():

  • Выполнение String.equals() сначала проверяет ссылочное равенство (используя ==), и если 2 строки одинаковы по ссылке, дальнейшие вычисления не выполняются!
  • Если две строковые ссылки не совпадают, String.equals() будет проверять длину строк. Это также является быстрой операцией, поскольку класс String хранит длину строки, не нужно считать символы или кодовые точки. Если длины отличаются, дальнейшая проверка не выполняется, мы знаем, что они не могут быть равными.
  • Только если мы доберемся до этого, будет фактически сопоставлено содержимое двух строк, и это будет короткое сравнение: не все символы будут сравниваться, если мы найдем несоответствующий символ (в том же положении в 2 строки), никакие другие символы не будут проверяться.

Когда все сказано и сделано, даже если у нас есть гарантия, что строки являются стажерами, использование метода equals() все еще не является издержками, которые можно подумать, определенно рекомендуемым способом. Если вам нужна эффективная проверка ссылок, то используйте перечисления, где гарантируется спецификацией и реализацией языка, что одно и то же значение перечисления будет одним и тем же объектом (по ссылке).

  • 2
    Obviously == is faster - фактически реализация .equals(String) сначала проверяет == прежде всего, поэтому я бы сказал, что скорость примерно одинакова.
  • 2
    public boolean equals(Object anObject) { if (this == anObject) { return true; } ...
88

== сравнивает ссылки на объекты в Java, и это не является исключением для объектов String.

Для сравнения фактического содержимого объектов (включая String) необходимо использовать метод equals.

Если сравнение двух объектов String с использованием == оказывается true, это связано с тем, что объекты String были интернированы, а виртуальная машина Java имеет несколько ссылок, указывающих на один и тот же экземпляр String. Не следует ожидать сравнения одного объекта String, содержащего то же содержимое, что и другой объект String, используя == для оценки как true.

75

Если вы похожи на меня, когда я впервые начал использовать Java, я хотел использовать оператор "==" для проверки того, были ли два экземпляра String равными, но, к лучшему или худшему, это не правильный способ сделать это в Java.

В этом уроке я продемонстрирую несколько разных способов правильно сравнить строки Java, начиная с подхода, который я использую большую часть времени. В конце этого руководства по сравнению с Java String я также обсужу, почему оператор "==" не работает при сравнении строк 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(), compareTo() и compare()

  • 5
    для строковых литералов, таких как String string1 = "foo bar"; String string2 = "foo bar"; Вы можете напрямую использовать оператор == для проверки равенства содержимого
  • 1
    В приложениях Google скрипт «Сравнить» невозможен. Я попробовал установить "равно" Это было единственное решение, которое работает ....
70

Оператор == проверяет, указывают ли две ссылки на один и тот же объект или нет. .equals() проверьте фактическое содержимое строки (значение).

Обратите внимание, что метод .equals() принадлежит классу Object (суперкласс всех классов). Вам необходимо переопределить его в соответствии с вашим требованием к классу, но для String оно уже реализовано и проверяет, имеют ли две строки одно значение или нет.

  • Случай 1

    String s1 = "Stack Overflow";
    String s2 = "Stack Overflow";
    s1 == s2;      //true
    s1.equals(s2); //true
    

    Причина: Строковые литералы, созданные без нуля, хранятся в пуле строк в области перменгенов кучи. Таким образом, оба s1 и s2 указывают на тот же объект в пуле.

  • Случай 2

    String s1 = new String("Stack Overflow");
    String s2 = new String("Stack Overflow");
    s1 == s2;      //false
    s1.equals(s2); //true
    

    Причина. Если вы создаете объект String с помощью ключевого слова new, ему присваивается отдельное пространство в куче.

70

Функции:

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);
  • 5
    Чем это отличается от других ответов? и почему это так, как вы предлагаете
  • 2
    @Mark На вопрос о разнице между == и equals уже отвечали другие решения, я просто предложил другой способ свободного сравнения строк.
47

Я думаю, что когда вы определяете String, вы определяете объект. Поэтому вам нужно использовать .equals(). Когда вы используете примитивные типы данных, вы используете ==, но с String (и любым объектом) вы должны использовать .equals().

  • 1
    Также обратите внимание, что == не работает для char []
  • 7
    "char []" не является примитивным типом данных! Это массив "char". И массивы сами по себе не являются примитивными типами данных.
47

== сравнивает опорное значение объектов, тогда как equals() метод присутствует в java.lang.String Класс сравнивает содержимое объекта String (к другому объекту).

  • 14
    не слишком придирчив, но метод equals() для String фактически находится в классе String , а не в Object . Значение по умолчанию equals() в Object не будет сравнивать, что содержимое одинаково, и на самом деле просто возвращает true, когда ссылка одинакова.
  • 1
    @JacobSchoen: приведенная выше ссылка больше не работает, так как GrepCode не работает. Вот альтернатива для равной реализации: [Встроенная ссылка] ( zgrepcode.com/java/openjdk/10.0.2/java.base/java/lang/… )
44

Если метод 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() каждый новый объект создается каждый раз.

40

Оператор == всегда предназначен для сравнения , тогда как метод 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)
37

Вы также можете использовать метод compareTo() для сравнения двух строк. Если результат compareTo равен 0, то две строки равны, в противном случае сравниваемые строки не равны.

== сравнивает ссылки и не сравнивает фактические строки. Если вы создали каждую строку с помощью new String(somestring).intern(), вы можете использовать оператор == для сравнения двух строк, в противном случае могут использоваться только методы equals() или compareTo.

35

В Java, когда оператор "==" используется для сравнения двух объектов, он проверяет, ссылаются ли объекты на одно и то же место в памяти. Другими словами, он проверяет, являются ли имена двух объектов в основном ссылками на одно и то же место в памяти.

Класс Java String фактически переопределяет реализацию equals() по умолчанию в классе Object, и он переопределяет метод, чтобы он проверял только значения строк, а не их местоположения в памяти.  Это означает, что если вы вызываете метод equals() для сравнения двух объектов String, то, пока действительная последовательность символов равна, оба объекта считаются равными.

Оператор == проверяет, являются ли две строки точно одним и тем же объектом.

Метод .equals() проверяет, имеют ли две строки одно и то же значение.

  • 1
    если только один из них не равен нулю, так как s.equals (s2) завершится сбоем, если s равно нулю, что приведет к сбою сравнения. Конечно, это на самом деле не противоречит ответу; это просто предостережение.
  • 1
    Нет, это не приведет к сбою, оно вызовет исключение NullPointerException, в результате чего сравнение не будет выполнено.
35

Все объекты гарантированно имеют метод .equals(), так как Object содержит метод .equals(), который возвращает логическое значение. Задача подкласса переопределять этот метод, если требуется дополнительное определение определения. Без него (т.е. С помощью ==) только адреса памяти проверяются между двумя объектами для равенства. String переопределяет этот метод .equals() и вместо использования адреса памяти возвращает сравнение строк на уровне символа для равенства.

Ключевое замечание состоит в том, что строки хранятся в одном пуле модулей, поэтому после создания строки он всегда сохраняется в программе с тем же адресом. Строки не меняются, они неизменяемы. Вот почему это плохая идея использовать регулярную конкатенацию строк, если у вас есть серьезное количество обработки строк. Вместо этого вы будете использовать классы StringBuilder. Помните, что указатели на эту строку могут измениться, и если вам было интересно увидеть, были ли два указателя одинаковыми, == был бы прекрасным способом. Строки сами не делают.

  • 2
    «после создания строки она навсегда сохраняется в программе по одному и тому же адресу» - это совершенно неверно. Только константные строковые выражения во время компиляции (возможно, включающие final String переменные) и строки, которые ваша программа явно интернирует, хранятся в том, что вы называете «комом пула». Все остальные объекты String подлежат сборке мусора, если на них больше нет живых ссылок, как и любой другой тип объекта. Кроме того, хотя для работы всего интернирующего механизма требуется неизменность, в остальном это не имеет значения.
  • 0
    Сравнение строк выполняется с помощью метода equalsIgnoreCase, который фактически сравнивает содержимое строки. Но == знак просто проверьте контрольные значения. Для строковых литералов из пула строк отлично подойдет для этого случая. String s1 = новая строка ("a"); String s2 = новая строка ("a"); в этом случае s1 == s2 ложно, но s1.equals (s2) верно.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню