为什么indexOf()和contains()不能像我在Java中预期的那样工作?

// Objects for the bookstore I created

BookStore bookStore = new BookStore("Subu's Book Store","Perambur");
bookStore.addItem(new Item("Animal Farm",20));
bookStore.addItem(new Item("Animal Farm",20));

如果我使用原始工作方法,则输出:

Animal Farm has been bought
Animal Farm is already bought

使用 contains() 不起作用的方法的输出

Animal Farm has been bought
Animal Farm has been bought

使用 indexof() 不起作用的方法的输出

-1
Animal Farm has been bought
-1
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index -1 out of bounds for length 1
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
at java.base/java.util.Objects.checkIndex(Objects.java:372)
at java.base/java.util.ArrayList.get(ArrayList.java:459)
at com.company.subusproject.BookStore.searchItem(BookStore.java:41)
at com.company.subusproject.BookStore.addItem(BookStore.java:16)
at com.company.subusproject.Main.main(Main.java:11)

这是有效的原始方法

public boolean searchItem(Item item) {
  for (int i = 0; i < this.myStocks.size(); i++) {
    Item foundItem = this.myStocks.get(i);
    if (foundItem.getName().equals((item.getName()))) {
      return true;
    }
  }
  return false;
}

这是我不知道为什么它不工作,我打算如何这个方法来工作,如果变量的方法searchingItem返回true,则该方法searchItem将返回如果没有返回false

public boolean searchItem(Item item) {
  // this method returns the boolean value true if found, if not returns false   
  boolean searchingItem = this.myStocks.contains(item);
  if(searchingItem){
    return true;
  } else {
    return false;
  }
}

这也不能按我的意图工作。我打算使用此方法的方式是,当我找到要查找的元素的索引位置,然后将其与列表myStocks中可用的元素进行比较时,在这种情况下也不是这种情况。

public boolean searchItem(Item item) {
  // this method returns the index number of the founded element, if not returns -1
  int itemPosition = this.myStocks.indexOf(item); // this line always returns -1 in this scenario
  for(int i=0; i<this.myStocks.size(); i++){
    if(myStocks.get(itemPosition).getName().equals(myStocks.get(i).getName())){
      return true;
    }
  }
  return false;
}

商店类以创建任何商店类

public abstract class Store {
  private String name;
  private String address;
    
  public Store(String name, String address) {
    this.name = name;
    this.address = address;
  }
    
  public abstract boolean addItem(Item item);
    
  public abstract boolean removeItem(Item item);
    
  public abstract boolean searchItem(Item item);        
}

基本项目类添加任何类型的项目

public class Item {
    
  private String name;
  private int price;
    
  public Item(String name, int price){
    this.name = name;
    this.price = price;
  }
    
  public String getName(){
    return this.name;
  }
    
  public int getPrice(){
    return this.price;
  }  
}
    

具有添加和搜索方法的实际书店类

public class BookStore extends Store {
        
  private List<Item> myStocks;
        
  public BookStore(String name, String address) {
    super(name, address);
    this.myStocks = new ArrayList<>();
  }
        
  public boolean addItem(Item item) {
    if (!searchItem(item)) {
      this.myStocks.add(item);
      System.out.println(item.getName() + " has been bought");
      return true;
    } else {
      System.out.println(item.getName() + " is already bought");
      return false;
    }
  }
        
  public boolean searchItem(Item item) {
    for (int i = 0; i < this.myStocks.size(); i++) {
      Item foundItem = this.myStocks.get(i);                
      if(foundItem.getName().equals((this.myStocks.get(i).getName()))) {
        return true;
      }
    }
    return false;
  }
}

显然,我知道我对它应该如何工作的假设是错误的,问题在于那些内置方法以及我希望它们如何工作,但事实并非如此。

回答

解决方案:

您必须实现equalshashCodein Item,因为contains依赖于equals.

如果equals默认情况下不覆盖Java,则使用引用相等。

从文档contains

返回true此列表是否包含指定的元素。更正式地说,true当且仅当此列表包含至少一个元素e使得(o==null ? e==null : o.equals(e)).

覆盖规则equals

部分取自此处:Java SE 定义了equals必须履行的合同。该equals方法必须是:

  • 自反:对象必须等于自身
  • 对称x.equals(y)必须返回相同的结果y.equals(x)
  • 传递性:如果x.equals(y)y.equals(z)随后也x.equals(z)
  • 一致equals仅当包含在其中的属性发生更改时,的值才应equals更改(不允许随机性)

为什么还要覆盖hashCode

也部分取自这里。Java SE 还为该hashCode方法定义了一个协定。彻底看看它显示了如何密切相关hashCode,并equals有。合同中的所有三个标准在hashCode某些方面都提到了equals方法:

  • 内部一致性: 的值hashCode可能仅在更改的属性时equals更改
  • 相等一致性:彼此相等的对象必须返回相同的哈希码
  • 碰撞:不相等的对象可能具有相同的哈希码(即,仅仅因为两个对象具有相同的哈希码并不意味着它们相等)

我建议使用 IDE 自动生成equals并且hashCode只使用final两种方法中的字段来确定它们的返回值。

只有遵循这些规则,我们才能期望标准库(或任何其他数据结构)中的数据结构正常工作。

  • @Basya 因为`equals` 的文档要求在覆盖`equals` 时也必须实现`hashCode`。方法在任何时候都可以依赖于这个事实。因此,即使 `contains` 今天可能不使用 `hashCode`,明天也可能会使用它。只需使用您的 IDE 自动生成这两种方法。

以上是为什么indexOf()和contains()不能像我在Java中预期的那样工作?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>