繁体   English   中英

如何避免在 ArrayList 中添加重复的对象?

[英]How can I avoid adding duplicated objects in an ArrayList?

我试图避免在 ArrayList 中添加重复的(学生)对象......我试图遍历数组并检查 ID 和 PhoneNO 但是使用这两个条件我无法添加任何 object 即使它是唯一的。 .. 另外,我尝试使用 contains() function 进行检查,但它不起作用,它允许添加重复的对象,我该如何解决?

    public void addStudent(Student newStudent) {
    //1-Looping over the ArrayList<student> and check their ID and PhoneNO (can't add any object of student)
    for(Student student:students) {
        if(newStudent.getId() == student.getId() || newStudent.getPhoneNumbre() == student.getPhoneNumbre()) {
            System.out.println("Error");
            break;
        }else
            this.students.add(newStudent);
    }
    
    //2- validate using the contains(), but it allows duplicated Objects
    if (!this.students.contains(newStudent)) 
        this.students.add(newStudent);
}

我的猜测是您的 Student Class 缺少 equals() 和 hashCode() 方法。

在 Student Class 中实现 equals() 和 hashCode() 方法。如果您使用 IDE,例如 Eclipse 或 IntelliJ,您也可以自动生成 equals() 和 hashCode() 方法。

此外,使用 HashSet 而不是 ArrayList。 HashSet 将防止插入重复项,因为一个集合只包含唯一的对象。 如果您必须使用 ArrayList,那么拥有 equals() 对于 ArrayList 的 contains() 方法正常工作很重要。 另外,请注意,如果两个 Student 对象相等,则它们的 hashCode 必须相同。

对于两个不同的 object 实例, ==运算符将始终返回false ,即使这两个实例相等。

在 Java 中, ==运算符测试同一性,而不是相等性(尽管如果两个事物相同,它们显然也相等)。

令人讨厌的是,在 Java 中,两个具有相同内容的明显不同的字符串可以相等相同——但这取决于底层 JVM 和其他条件。 意思是,你不应该依赖这个!

因此,如果Student::getIdStudent::getPhoneNumbre确实返回 object 引用而不是基元,则需要将它们与Object::equals进行比较:

if( newStudent.getId().equals( student.getId() ) 
    || newStudent.getPhoneNumbre().equals( student.getPhoneNumbre() ) ) …

我假设您知道当至少 id电话号码相等时,您的逻辑将新学生识别为现有学生的副本。

否则,当副本要求两者相等时,您应该考虑为 class Student实现方法Object::equals 这将简化检查:

if( newStudent.equals( student ) ) …

equals()的实现可能如下所示:

@Override
public final boolean equals( Object o )
{
  final var retValue = (this == o)
    || (o instanceof Student other
        && Objects.equals( getId(), other.getId() )
        && Objects.equals( getPhoneNumbre(), other.getPhoneNumbre() ));
  
  return retValue;
}

请记住,强烈建议您在实现Object::equals ::equals 时始终同时实现Object::hashCode ,反之亦然——即使您目前只需要其中一种方法!

哦,在您的原始代码中,您需要确保Student::getIdStudent::getPhoneNumbre不会返回null 我建议的equals()实现已经解决了这个问题。


如果您不坚持使用List的实现来存储Student实例,则应该考虑使用Set的实现:一旦您提供了Student.equals()Student.hashCode() ,它就会在插入时自动进行重复检查.

如果通过 id 或电话号码识别重复项,您甚至可以使用Set实现,但这有点令人讨厌(尽管它工作得很好):

Set<Student> students = new TreeSet( (s1,s2) -> Comparator.naturalOrder.compare( s1.getId(), s2.getId() ) * Comparator.naturalOrder.compare( s1.getPhoneNumbre(), s2.getPhoneNumbre() ) );
…
if( !students.add( newStudent ) ) out.println( "Duplicate!" )

承认,output 的顺序会很奇怪,但这很容易修复……

此处Comparator的实现假定 id 和电话号码将实现Comparable


最后, List::contains对您不起作用,因为它要求您正确实施Student::equals 如果您没有覆盖该方法,则contains()检查身份,而不是相等性。

尝试使用 set(allows no duplicates),如下所示:

Set<Student> student = new HashSet<>();
student.add(new Student());

然后将集合转换为列表,现在将具有不同的学生记录

List<Student> studentList= new ArrayList<>(student);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM