包含与 ObservableList () 返回总是 false



im 在我的 JavaFX 代码中使用 ObservableList ,我正在尝试测试此列表中是否存在对象,但即使对于其中已经存在的对象,它也总是返回 false。 这是我的代码:

private ObservableList<OMission> UserMission = FXCollections.observableArrayList();    
OMission OM1 = new OMission(1,"user_firstname","user_lastname");

UserMission.add(OM1);

if(UserMission.contains(new OMission(1,"user_firstname","user_lastname")){
System.out.println("true");}
else {
System.out.println("false");
}

我期待得到"真实",但我总是得到虚假

发生了什么事情?

您可能忽略了实现equalshashCode的关键Object覆盖。

此问题并非特定于 OpenJFX 类ObservableList。任何执行比较的集合(列表、集合、映射等)都取决于您至少为equals编写适当的覆盖,也可能hashCode。(提示:始终覆盖两者或两者都不覆盖,切勿单独覆盖一个。

下面是使用修改后的代码版本的示例代码。顺便说一下,你缺少一个右括号。此外,如果您遵循 Java 命名约定,生活会更轻松。

为了简洁起见,我们使用 Java 16+ 中的新记录功能。记录是编写类的简短方法,该类的主要目的是透明且不可变地传达数据。您只需声明每个成员字段的类型和名称。编译器隐式创建构造函数、getter、equals&hashCodetoString。默认情况下,最后三种方法检查每个成员字段的值。

为简单起见,我们在本地声明了record。您也可以将其声明为嵌套或分离。

package work.basil.example;
import javafx.collections.*;
public class App {
public static void main ( String[] args ) {
System.out.println ( "Hello World!" );
App app = new App ();
app.demo ();
}
private void demo () {
record Person( int id , String firstName , String lastName ) { }
ObservableList < Person > UserMission = FXCollections.observableArrayList ();
Person p1 = new Person ( 1 , "Alice" , "Anderson" );
UserMission.add ( p1 );
if ( UserMission.contains ( new Person ( 1, "Alice" , "Anderson" ) ) ) {
System.out.println ( "true" );
} else {
System.out.println ( "false" );
}
}
}

运行时。

世界您好!

如果使用早期版本的 Java,或者记录不适合您的情况,请编写类似于以下内容的类。请注意方法equalshashCode

package work.basil.example;
import java.util.Objects;
public final class Person {
private final int id;
private final String firstName;
private final String lastName;
public Person ( int id , String firstName , String lastName ) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
public int id () { return id; }
public String firstName () { return firstName; }
public String lastName () { return lastName; }
@Override
public boolean equals ( Object obj ) {
if ( obj == this ) return true;
if ( obj == null || obj.getClass () != this.getClass () ) return false;
var that = ( Person ) obj;
return this.id == that.id &&
Objects.equals ( this.firstName , that.firstName ) &&
Objects.equals ( this.lastName , that.lastName );
}
@Override
public int hashCode () {
return Objects.hash ( id , firstName , lastName );
}
@Override
public String toString () {
return "Person[" +
"id=" + id + ", " +
"firstName=" + firstName + ", " +
"lastName=" + lastName + ']';
}
}

覆盖equals/hashCode的问题已经涉及了很多次。搜索以了解更多信息。

Basil 同时更新了他的答案,在我写这篇文章时包含了一些额外的信息。 因此,此答案中重复了一些信息。 请原谅此处的任何重复。 我暂时保留这个答案。


为了补充Basil的答案,一些不同的解决方案是:

  1. 编写等号和哈希码的自定义实现。

对于OMission,实现equals(Object obj)(最好也实现hashCode())。

你最终会得到像 Basil 的示例答案一样的代码。

您可以自己从头开始编写这些方法,但是,我不建议这样做。 在手动编写这些函数时,很容易犯不必要的愚蠢错误。

  1. 使用 IDE 自动生成等号和哈希码的实现。

大多数 IDE 都有一个菜单项或快捷方式来自动生成这些方法(请参阅如何在 Idea 中执行此操作)。 这就是我通常生成这些函数的方式。 如果我在类中添加或删除字段,则删除以前的自动生成函数并自动生成新函数。

  1. 使用第三方库生成等号和哈希码。

第三方库(如龙目岛)可用于自动生成方法。龙目岛将通过注释来做到这一点,例如,只需将注释@EqualsAndHashcode添加到您的类定义中。

  1. 使OMission成为记录而不是类。

如果数据可以表示为不可变记录而不是类是合适的,那么建议使用此方法。 它不适用于所有数据类型。

默认情况下,记录实现适当的等于和哈希码方法。

record OMission(
int missionNum, 
String firstname, 
String lastname
) {}

最新更新