Java中ArrayList的indexOf()和contains()方法未按预期运行如何解决
问题根本原因
- 首先,Java
ArrayList的contains()和indexOf()方法底层依赖equals()方法判断两个对象是否相等。你当前的Item类没有重写equals()方法,默认使用Object类的原生equals()逻辑,仅判断两个对象的内存地址是否相同。你两次添加的是new出来的两个独立Item对象,即使属性完全一致,地址也不同,所以contains()永远返回false,indexOf()永远返回-1。 - 其次,
indexOf版本的searchItem逻辑存在明显错误:你没有判断itemPosition是否为-1就直接传入myStocks.get()方法,List不允许负数索引,自然会抛出数组越界异常,而且后续的循环逻辑完全冗余,没有存在的必要。 - 补充:你贴出的
BookStore实现类中自带的searchItem存在逻辑错误,foundItem.getName().equals((this.myStocks.get(i).getName()))是同一个对象的属性自比较,只要列表不为空就永远返回true,和你第一个正常运行的手动遍历实现逻辑不符。
正确解决办法
第一步:给Item类重写equals()和hashCode()方法
Java规范要求:如果两个对象equals()返回true,它们的hashCode()必须返回相同值,因此两个方法要一起重写,避免后续在HashSet、HashMap等哈希结构集合中使用时出现逻辑异常。
重写后的Item类代码示例:
import java.util.Objects; 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; } // 重写equals方法,按业务逻辑判断相等:名称和价格都相同则视为同一个商品 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Item item = (Item) o; return price == item.price && Objects.equals(name, item.name); } // 同步重写hashCode方法 @Override public int hashCode() { return Objects.hash(name, price); } }
如果你业务上只要求名称相同就算同一个商品,equals()里去掉价格判断即可。
第二步:修正searchItem实现
基于contains()的正确版本
public boolean searchItem(Item item) { return this.myStocks.contains(item); }
原实现的if-else判断完全冗余,直接返回contains()的结果即可。
基于indexOf()的正确版本
public boolean searchItem(Item item) { int itemPosition = this.myStocks.indexOf(item); return itemPosition >= 0; }
直接判断索引是否为非负数即可,无需额外循环,也避免了越界问题。
内容的提问来源于stack exchange,提问作者mockingbird
相关产品推荐
相关产品推荐

