繁体   English   中英

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

[英]Why indexOf() and contains() doesn't work as i intended in 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));

Output如果我用原来的工作方式:

Animal Farm has been bought
Animal Farm is already bought

Output 对于使用 contains() 不起作用的方法

Animal Farm has been bought
Animal Farm has been bought

Output 对于使用 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;
  }
}

这也不按我的预期工作。 我打算使用此方法的方式是,当我找到要查找的元素的索引 position,然后将其与列表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;
}

Store class 创建任意店铺 class

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);        
}

基础项目 class 添加任意项目

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;
  }  
}
    

实际的书店 class 其中有添加和搜索的方法

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;
  }
}

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

解决方案:

您必须在Item中实现equalshashCode ,因为contains依赖于equals

如果您不覆盖equals Java,则默认使用引用相等

contains的文档:

如果此列表包含指定元素,则返回true 更正式地说,当且仅当此列表包含至少一个满足(o==null? e==null: o.equals(e))的元素e时才返回true

覆盖equals的规则:

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

  • 自反:object 必须等于自身
  • 对称x.equals(y)必须返回与y.equals(x)相同的结果
  • 传递性:如果x.equals(y)y.equals(z)那么也x.equals(z)
  • consistent :只有当包含在equals中的属性发生变化时, equals的值才应该改变(不允许随机性)

为什么还要覆盖hashCode

也部分取自这里 Java SE 还为hashCode方法定义了一个契约。 仔细观察它可以看出hashCodeequals的关系有多密切。 hashCode契约中的所有三个标准都以某种方式提到了equals方法:

  • 内部一致性hashCode的值可能仅在equals中的属性发生变化时发生变化
  • 等于一致性:彼此相等的对象必须返回相同的 hash 代码
  • 碰撞:不相等的对象可能具有相同的 hash 代码(即,仅仅因为两个对象具有相同的 hash 代码并不意味着它们是相等的)

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

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

您需要在Item class 中实现equals()方法, contains()indexOf()在内部使用equals()方法。 也因为它是合同中的,所以你必须实现hascode()方法,这将确保没有违约。

如果您不实现哈希码,它将基于 JVM 实现占用 memory 位置,这将始终为等于 object 返回不同的 int,当您使用项目 object 作为 hashmap 中的键时,它会失败,它在哈希 81811498 时的性能也取决于 8111493关于 Hascode 实现(很长的主题,所以不详细介绍)。

阅读javadoc

暂无
暂无

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

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