Java: почему не работает метод Equals?

1

Я применил метод equals в объекте Person с @annotation, однако, когда я создаю объект в своем основном классе и проверяю его на объекты List of Person, он не возвращает правильный индекс. В нем говорится, что они оба равны 1, но это должно быть 1 и 3.

Задача:

Проверьте, существует ли в моем списке "Энди Бернард", и если да, отобразите индекс объектов.

import java.util.ArrayList;
import java.util.List;

public class Person {
    private String firstName;
    private String lastName;

    public Person(String firstName,String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @Override 
    public String toString() {
        return String.format(this.firstName + " " + this.lastName);  
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((firstName == null) ? 0 : firstName.hashCode());
        result = prime * result
                + ((lastName == null) ? 0 : lastName.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        if (firstName == null) {
            if (other.firstName != null)
                return false;
        } else if (!firstName.equals(other.firstName))
            return false;
        if (lastName == null) {
            if (other.lastName != null)
                return false;
        } else if (!lastName.equals(other.lastName))
            return false;
        return true;
    }

    private static List<Person> deletePeople = new ArrayList<>();

    public static void main(String[] args) {
         addPerson("Micheal","Scott");
         addPerson("Andy","Bernard");
         addPerson("Micheal","Scott");
         addPerson("Andy","Bernard");
         display();

    }

    public static void addPerson(String firstname, String lastname) {
        Person createPerson = new Person(firstname,lastname);
        deletePeople.add(createPerson);
    }

    public static void display() {
        Person checkPerson = new Person("Andy","Bernard");

        for (Person display : deletePeople) {
            if(display.equals(checkPerson)) {
                System.out.println((display.getFirstName() + " " +
                display.getLastName() + " " + deletePeople.indexOf(display)));
            }
        }
    }
}
  • 0
    я думаю, что вы должны использовать хеши / карту, так как проблема indexOf, он возвращает первое вхождение, и у вас есть 2 одинаковых человека
  • 0
    Ваш код не завершен. Что такое deletePeople ? Где это заявлено?
Показать ещё 2 комментария
Теги:
collections

2 ответа

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

indexOf возвращает индекс первого вхождения, который является одним и тем же (в соответствии с методом equals) в List. Вот почему вы видите, что и один напечатан.

Возвращает индекс первого вхождения указанного элемента в этом списке или -1, если этот список не содержит этот элемент. Более формально возвращает наименьший индекс я такой, что (o == null? Get (i) == null: o.equals(get (i))) или -1, если такого индекса нет.

И вы можете увидеть реализацию (для ArrayList, но ту же идею для LinkedList за исключением того, что вы итерации других узлов):

229  public int indexOf(Object o) {
230      if (o == null) {
231          for (int i = 0; i < size; i++)
232              if (elementData[i]==null)
233                  return i;
234      } else {
235          for (int i = 0; i < size; i++)
236              if (o.equals(elementData[i]))
237                  return i;
238      }
239      return -1;
240  }

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

int index = 0;
for (Person display : deletePeople) {
    if(display.equals(checkPerson)){
        System.out.println((display.getFirstName() + " " + display.getLastName() + " " + index));
    }
    index++;
}

Это также было бы возможно со стандартом для цикла.

for(int i = 0; i < deletePeople.size(); i++){
    Person display = deletePeople.get(i);
    if(display.equals(checkPerson)){
        System.out.println((display.getFirstName() + " " + display.getLastName() + " " + i));
    }
}

Однако будьте осторожны с последней реализацией, потому что если базовое представление списка является LinkedList сложность вышеуказанного цикла будет O(n^2) вместо O(n).

  • 0
    @ ZouZou - Что я могу сделать, чтобы это исправить?
  • 0
    @Nexusfactor зачем тебе список? тебе действительно нужны дубликаты? Если это так, вы должны пройтись по списку; если нет, используйте набор.
Показать ещё 5 комментариев
0

indexOf() вы печатаете первый индекс, который соответствует, а не текущий индекс. Если вам интересно отслеживать свою позицию в списке, лучше всего это сделать вручную, поэтому вместо цикла for-each:

for(Object o : ls) {
  // the syntax is nice, but we don't have an easy way to
  // tell how far into the list we are
  System.out.println(o);
}

Вместо этого используйте простой цикл:

for(int i = 0; i < ls.size(); i++) {
  Object o = ls.get(i);
  // Now we have access to the object *and* its index
  System.out.println(i+": "+o);
}

Кроме того, в вашем коде есть несколько простых исправлений, если вы простите меня, вот несколько советов:

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

    public Person(String firstName,String lastName) {
      if(firstName == null || lastName == null) {
        throw new NullPointerException("First/Last name cannot be null");
      }
      this.firstName = firstName;
      this.lastName = lastName;
    }
    
  2. Используйте String.format() правильно или просто избегайте этого. Ваш текущий метод toString() вызывает String.format(this.firstName + " " + this.lastName), который на самом деле ничего не делает; вы можете просто вернуть конкатенированную строку без String.format(). Кроме того, вы можете правильно использовать функциональные возможности формата:

    String.format("%s %s", firstName, lastName);
    
  3. Воспользуйтесь классом Java 7 Objects для ваших методов hashCode() и equals():

    @Override
    public int hashCode() {
        return Objects.hash(firstName, lastName);
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        return Objects.equals(firstName, other.firstName) &&
               Objects.equals(lastName, other.lastName);
    }
    
  • 0
    - Спасибо за разъяснения и исправления, очень ценю. Этот код был только для моего собственного понимания, и это не для какого-либо конкретного проекта. Я уже знаю, как не создавать объект с нулевыми значениями, но не удаляю и не удаляю ваш ответ. Это будет полезно для меня в будущем, если это необходимо.

Ещё вопросы

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