.equals() для пользовательского класса в Java

Пожалуйста, смотрите код ниже

class TestToString 
{
  public static void main(String args[]) 
  {
    CheckToString cs = new CheckToString (2);
    CheckToString c = new CheckToString (2);
    if( cs.equals(c))
       System.out.println(" Both objects are equal");
    else
       System.out.println(" Unequal objects ");
  }
}

class CheckToString 
{
   int i;
   CheckToString () 
   {
      i=10;
   }
   CheckToString (int a) 
   {
     this.i=a;
   }
}

Вывод: неравные объекты

Но я ожидал, что результат будет

Оба объекта равны

Я понял, что оба объекта имеют разные ссылки,

System.out.println(cs); //com.sample.personal.checkToString@19821f
System.out.println(c); //com.sample.personal.checkToString@addbf1

но я спрашивал, почему у них разные ссылки? тогда как в приведенном ниже случае объекты имеют одинаковые области памяти.

Integer a = new Integer(2);
Integer b = new Integer(2);
System.out.println(a);           //2
System.out.println(b);           //2

Я сравниваю объект пользовательского класса с объектом предварительно определенного класса. Кажется, что объект пользовательского класса ведет себя так же, как и объект целочисленного класса, значение которого превышает от -128 до 127. Почему ссылки различны в обоих случаях? (то же самое для класса Integer, имеющего значение в диапазоне от -128 до 127 и различного для пользовательского класса)

6 ответов

Реализация по умолчанию equals проверяет ссылки. Вы создаете 2 разных объекта, которые не ссылаются на одну и ту же вещь в памяти.

Достойная реализация equals будет что-то вроде:

public boolean equals(Object o) {
  if (!(o instanceof CheckToString)) {
    return false;
  }
  CheckToString other = (CheckToString) o;
  return i == other.i;
}

При переопределении equalsнужно переопределить hashCode, тоже.

Всякий раз, когда вы говорите new CheckToString(), вы создаете новый объект в памяти, так что совершенно другая ссылка, чем другой new CheckToString(), Неважно, что находится внутри определения объекта.

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

Вы должны переопределить equals метод в вашем CheckToString учебный класс:

@Override
public boolean equals(Object o){
   if(this==o){
      return true;
   }
   if(o instanceof CheckString){
       CheckString other = (CheckString) o;
       return this.i == other.i;
   }
   return false;
}

Рекомендуется при переопределении equals Вы также переопределите hashCode, так что вы можете использовать свой объект в хешированных коллекциях (например, HasSet, LinkedHasSet, HashMap). В таком случае, поскольку ваш класс выглядит как обертка над примитивным целым числом, я думаю, вы могли бы вернуть само целое число.

@Override
public int hashCode(){
   return i;
}

И, наконец, всегда рекомендуется переопределить toString, так что каждый раз, когда вы смотрите на экземпляры вашего класса, вы видите дружественное, удобочитаемое представление вашего объекта.

@Override
public String toString(){
   StringBuilder sb = new StringBuilder();
   sb.append(this.getClass().getSimpleName()).append("[");
   sb.append("i: ").append(i).append("]");
   return sb.toString();
}

Вы должны определить свой собственный метод toString для возврата значения i И ваш собственный метод равных.

class checkToString
{
   int i;
   public checkToString()
   {
      i=10;
   }
   public checkToString(int a)
   {
     this.i=a;
   }

   public String toString(){ return "" + i;}
   public boolean equals(checkToString a){ return a.toString().equals(this.toString());} 
}

Попробуйте сейчас. Это также может быть сделано без toString().

как это:

public boolean equals(checkToString a){ return (this.i == a.i); }

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

Чтобы сравнить их строковое представление, вы можете сделать эту модификацию:

class TestToString
 {
  public static void main(String args[])
   {
    CheckToString cs = new CheckToString(2);
    CheckToString c = new CheckToString(2);
    if( cs.toString().equalsIgnoreCase(c.toString()))
       System.out.println(" Both objects are equal");
    else
       System.out.println(" Unequal objects ");
 }
}


class CheckToString
{
   int i;
   CheckToString()
   {
      i=10;
   }
   CheckToString(int a)
   {
     this.i=a;
   }
   public String toString(){
    return String.valueOf(i);
   }
}

PS: Обратите внимание также на изменение в случае объекта ( Java Conventions)

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

Метод equals сравнивается на основе ссылки по умолчанию в любом определяемом пользователем классе, но если вы переопределяете метод equals в текущем классе, то он сравнивается на основе содержимого... но в java.lang.StringClass он сравнивается по основа содержания всегда

Другие вопросы по тегам