Как сравнивать правильно Strings (и объекты) в Java?

Я создаю мини игру, в которой пользователь пробует угадывать имя. Но когда я хочу сравнить две цепи текста, чтобы видеть, равны ли они оно, кажется, не функционирует.

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!
76
задан 09.08.2017, 19:33
9 ответов

В Java только примитивные типы (Описанные в JLS (§4.2), например int или char) они сравниваются с ==, Strings (и остальные объекты) в Java они сравниваются между ними с методом equals.

String#equals(Object)

Сравни этот String с определенным объектом. Результат true если, и только, если аргумент не null и это объект типа String что представляет ту же последовательность символов, что и этот objecto.


  • JLS (§15.21.3) Хотя он может использоваться == чтобы сравнивать ссылки типа String, доказательство равенства определяет, если два operandos передают тот же объект String. Результат false если operandos - различные объекты String, даже, если они содержат ту же последовательность символов.

Следовательно твое сравнение должно быть:

if(miNombre.equals(intento)) {

Выход:

Adivina mi nombre: 
manuel
Intentalo de nuevo!
Jordi
Acertaste!

РАЗЪЯСНЕНИЯ:

  • Я поместил переменную miNombre в начале сравнения, чтобы предотвращать одну NullPointerException если intento == null (если, сравнения с null также они делаются с ==).

    Как дополнительный: если null это действительная стоимость в представлении (и следовательно мы хотим предотвратить одну NPE), Objects.equals будь доступен начиная с Java 7 и он берется за то, чтобы возвращать true, если оба null или false если это только это одна.

  • В этом случае возможно использовать метод String#equalsIgnoreCase(Object) который он проигнорирует MAYUSCULAS или MINUSCULAS сделав сравнение:

    if(miNombre.equalsIgnoreCase(intento)) {       
    
  • JLS (§15.21) Операторы равенства (== и !=) они могут использоваться для того, чтобы сравнивать два operandos, что преобразуемые (§5.1.8) числового типа, или два operandos типа boolean или Boolean или два operandos, что > они типа ссылки или типа null. Все остальные случаи вызывают ошибку во времени компиляции.

102
ответ дан 01.12.2019, 08:17
  • 1
    Как дополнительный: если null - стоимость v и # 225; lido в representaci и # 243; n (и следовательно мы хотим предотвратить NPE), Objects.equals est и # 225; доступный начиная с Java 7 и он берется за то, чтобы возвращать true, если оба null или false, если s и # 243; это это одна. – Darkhogg 02.12.2015, 19:31
  • 2
    Дополнительный: используй intento.intern() == miNombre.intern() вместо equals: P –  25.02.2016, 06:01

С Java 7 возможный сравнивать равенство двух strings используя метод equals класса java.util.Objects. Это:

String a = ...
String b = ...

if (Objects.equals(a, b)) {
    // iguales
} else {
    // diferentes
}

Так как a.equals(b) или b.equals(a) они могут бросать java.lang.NullPointerException если a он null или b он null соответственно, использовав эту дорожку, a или b они могут быть null без какого-либо риска.

Если ты используешь Java 6 (или несовершеннолетний), начиная с кода этого класса, мы можем повторно писать наше if следующего способа:

if (a == b || (a != null && a.equals(b))) {
    // iguales
} else {
    // diferentes
}
30
ответ дан 01.12.2019, 08:17
  • Оператор "==" сравнивает две ссылки, а именно, возвращает true , если оба объекта занимают ту же самую posiciГіn памяти.

  • mГ©todo "equals" сравнивает стоимость объектов.

21
ответ дан 01.12.2019, 08:17

В языке Java Гєtiliza она funciГіn equals(), чтобы сравнивать strings, КОГДА БЫ ТО НИ БЫЛО deberГ, - когда оператор == быть использованным.

String nombre = "elenasys";

if (nombre.equals("elenasys")) { //Correcto para comparar strings!
    ...
}

if (nombre == "elenasys") {   //Incorrecto para comparar strings!
    ...
}

Восток - ошибка comГєn в новых разработчиках.

16
ответ дан 01.12.2019, 08:17

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

Сравнивать их посредством equals почти всегда - лучшее решение

String cadena1="Hola";
String cadena2="Hola";
System.out.println(cadena1.equals(cadena2)); //funciona

String cadena1;
String cadena2="Hola";
System.out.println(cadena1.equals(cadena2)); //funciona

Но несмотря на это, у тебя могли бы быть проблемы, если твоя виртуальная машина меньше в Tiger, так как в несчастливых осуществлениях определенная цепь как null это не было тем же самым, что и пустая цепь.

String cadena1="";
String cadena2=null;
String cadena3;
System.out.println(cadena1.equals(cadena2).equals(cadena3));

Так что для этих случаев ты можешь использовать сравнение посредством оператора ==

String cadena1="Hola";
String cadena2="Hola";
System.out.println(cadena1 == cadena2); //funciona porque ya están inicializadas

Или имея много размести, сравнивая внутренние представления.

String cadena1="Hola";
String cadena2="Hola";
System.out.println(cadena1.intern() == cadena2.intern()); //son iguales solamente si cadena1.equals(cadena2)
7
ответ дан 01.12.2019, 08:17

" ==" он используется для Integer, Char, Object, или null, между другими, лучше использует equals или equalsIgnoreCase:

 final String miNombre = "Jordi";
Scanner input = new Scanner(System.in);
System.out.println("Adivina mi nombre: ");

while (true) {
    String intento = input.next();
    if(intento.equalsIgnoreCase(miNombre)) { //Tu puedes usar equals para que sea igual y equalsIgnoreCase para que se igual ignorando las mayúsculas && minúsculas, es decir que por mas que escribas JoRdI va a ser "true".
        System.out.println("Acertaste!");
        break;
    } else {
        System.out.println("Intentalo de nuevo!");
    }
}
7
ответ дан 01.12.2019, 08:17
  • 1
    explicació n, где он используется ' ==' он смелый. Есть много использований, чтобы сравнивать Object с equals () , вероятно má s, что для obj1 == obj2. – Stefan Nolde 08.01.2017, 08:53

Правильный способ сравнивать 2 Strings - посредством нее funciГіn equals () , который - это, чтобы сравнивать 2 цепи и equalsIngnoreCase () , который является тем же самым, но игнорируя их mayГєsculas и minГєsculas.

Пытается с:

if(intento.equalsIgnoreCase(miNombre)){
     System.out.println("Has Acertado");
}
else{
     System.out.println("Incorrecto");
}
6
ответ дан 01.12.2019, 08:17
  • 1
    Этот ответ ничего не вносит существенно различно в уже отвеченное из-за dem и # 225; в. – dwarandae 16.10.2016, 04:42

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

С == сравниваются ссылки и не контент объектов в памяти.

6
ответ дан 01.12.2019, 08:17
  • 1
    Этот ответ ничего не вносит существенно различно в уже отвеченное из-за dem и # 225; в. – dwarandae 15.10.2016, 23:56

Ты можешь осуществлять mГ©todo String.equals (""); который та же API java приносит asГ - как tambiГ©n ты, должно быть, осуществляешь соответствующие утверждения как они: реализовывать cadena.trim (); в текст, который ты хочешь санкционировать, так как место также считает во время нее comparaciГіn. этот mГ©todo то, что он реализует, состоит в том, чтобы снимать место в конце концов и в начале цепи. tambiГ©n ты можешь включать cadena.lengt (); чтобы реализовывать твои утверждения все зависит от твоей необходимости. привет Простой пример:

String micadena="Hola mundo";
String cadenaGuardada="Hola mundo";

if(micadena.equals(cadenaGuardada))
return "iguales";
else
return "No son iguales";
2
ответ дан 01.12.2019, 08:17

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

Цепи - Объекты как любой, но есть большие и тонкие различия, которые это отделяют оставшейся части Объектов, прежде всего ты можешь инициализировать цепь этих двух форм.

String usandoLiteral = "Mi literal"; // Por medio de un literal
String usandoNew = new String("Con operador new"); // Utilizando el operador clasico new

В обоих случаях создан объект, отсутствие оператора new в первом примере это только закладка (так он оказывается более натуральным).

Сейчас есть, что такое понимание как Java управляет о цепях, в Java существуй этот Стринг Пооль - место памяти, размещенное, чтобы хранить цепи, приложение обычно делает сильное использование Strings и только им может удаваться занять этих до 40 % памяти в runtime и многие из этих String's повторены например 'в' 'в' и т.д. Чтобы это оптимизировать Java коллекционирует все эти цепи как буквальные в расположении JVM и повторно использует буквальных, повторенных, чтобы оптимизировать использование памяти, таким образом, если ты хранишь буквальный "carlos" в двух переменных, Java повторно использует буквальный.

По этой причине, если ты объявляешь следующие переменные String и ты инициализируешь их с самим буквально. (он помнит, что ты создаешь два Объекта)

String nombre = "carlos";
String nombre2 = "carlos";

Сравнение с оператором == возвратится true, потому что Стринг Пооль перерабатывает буквальный "carlos", и поэтому это та же ссылка, следовательно полностью стоится делать сравнение.

Boolean sonIguales = nombre == nombre2; // sonIguales tiene el valor true

Стринг Пооль только перерабатывает и хранит буквальные, это означает, что, если ты создаешь цепь следующего способа

String nombre3 = new String("carlos");

После того, как не инициализировался буквальным java он это не будет хранить в Стринг Пооль и не будет переработки следовательно он будет удален Гарбахе Кольектор, если это будет так тогда, следующее сравнение последует в false.

Boolean esIgualAlTercero = nombre == nombre3; // esIgualAlTercero tiene el valor false.

Это разум, потому что, когда ты делаешь сравнение с оператором == часто, он даст тебе true и он другие тебе даст false несмотря на то, что ты сравниваешь ту же стоимость в цепи.

Метод .equals ты это используешь, когда ты хочешь сравнить цепь из-за стоимости или символа из-за символа, это безопасный способ делать сравнение цепей, так как он помнит, что, как в первом примере мы технически сделали сравнение из-за стоимости с оператором == ввиду своеобразия Стринг Пооль.

Добавочное замечание если ты осведомляешься об этом, если после того, как инициализирует цепь из-за буквального, стоимость хранится в Стринг Пооль, который происходит, когда я изменяю цепь?

Так как это другая точка, цепи в Java неизменные, это означает, что ты не можешь изменять Вашу стоимость например добавлять больше символов к стоимости String, и Java не предоставляет никакого API, чтобы изменять String прямо. (однако Java предоставляет API, чтобы мочь делать это косвенно)

Например, если я хочу добавить фамилию к моему изменчивому (имени), то, что я могу делать, состоит re в том, чтобы распределять в переменную (имя) новую цепь, что я построю ее прилагая первоначальную стоимость с фамилией таким образом.

nombre = nombre + " lucero"; 

Это, что он делает, состоит в том, чтобы создавать новую стоимость "carlos звезда" и распределять эту стоимость цепи назвало.

Сейчас, когда оно происходит, если я сейчас сравниваю 'имя' с новой переменной, которая содержала бы ту же стоимость, которую он 'называет', но распределенная как буквально?

String nombreCompleto = "carlos lucero";
Boolean esNombreCompletoIgual = nombreCompleto == nombre; // recuerda que nombre ahora tiene el valor "carlos lucero"

Так как как переменная (имя) он пошел re распределенная в новую стоимость, которую не была создана посредством буквального, так как сейчас переменная (имя) уже не в Стринг Пооль следовательно, Ваша ссылка, она не переработана и сравнение с переменной (nombreCompleto), что, если он был создан посредством буквального, даст как результат False.

В конце концов Java предоставляет API, чтобы оплачивать проблему неизменности цепей, эта API выставлена классом StringBuilder.

10
ответ дан 03.12.2019, 23:22
  • 1
    Хотя это не отвечает в OP, я проголосовал за нее, потому что он объясняет có mo функционируют цепи (объекты " String") в Java. –  02.01.2017, 00:16
  • 2
    @Jose4Linux así он, уже они ответили, когда использовать, и когда нет, querí чтобы дополнять объясняя причину, и потому что иногда может функционировать оператор == и иногда не, спасибо pro обет –  02.01.2017, 01:56
  • 3
    Когда ты имеешь в виду ответы má s старые, пожалуйста имей в виду, что " anteriores" смоги запутывать в случае, который порядок ответов может менять на оценки. –  18.01.2017, 08:02

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

Остается объяснять немного на методе equals () Все классы в Java - субклассы Object, object он приходит с назначенным по умолчанию заявлением equals ().

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

public class Point(){
    private int x;
    private int y;

    public Point(intx, int y){
        this.x=x;
        this.y=y;
    }

    public int getX() {return x;}

    public int getY() {return x;}

    @Override
    public boolean equals(Object o){
        return o instanceof Point && ((Point)o).getX()==x && ((Point)o).getY()==y;
    }
}

Если заявил субкласс Point с этикеткой как:

public class NamedPoint extends Point{

    private String etiqueta;

    public NamedPoint(int x, int y, String etiqueta){
        super(x,y);
        this.etiqueta=etiqueta;
    }

    public String getEtiqueta(){ return etiqueta }
}

он был бы должен комментировать, что два NamedPoint считаются равными, если координатные соответствуют, независимо от этикетки.

Глаз, просто sobreescribir метод не гарантирует связность в моей логике. Если sobreescribo equals в NamedPoint, чтобы также считать этикетки, он у меня остается со следующей проблемой:

Point point = new Point(3,6);
Point otroPoint = new NamedPoint(3,6,"Foo");
boolean equals1 = point.equals(otroPoint); // resultado true
boolean equals2 = otroPoint.equals(point); // resultado false

чтобы убегать эта двусмысленность могут сравниваться классы вместо того, чтобы использовать instanceof:

    @Override
    public boolean equals(Object o){
        return this.getClass().equals(o.getClass()) 
            && ((Point)o).getX()==x && ((Point)o).getY()==y;
    }

Они обобщают: есть драконы в теме равенства.

8
ответ дан 03.12.2019, 23:22

Теги

Похожие вопросы