List的removeAll()方法与equals()方法之坑

最新在项目中遇到一个坑,大概如下:

public class MainTest {

    public static void main(String[] args) {
        //创建一个List1对象,添加四个元素
        List<Operator> list1 = new ArrayList<>();
        Operator op1 = new Operator(0, "first operator", "1");
        Operator op2 = new Operator(0, "second operator", "2");
        Operator op3 = new Operator(0, "second operator", "2");
        Operator op4 = new Operator(0, "second operator", "3");
        list1.add(op1);
        list1.add(op2);
        list1.add(op3);
        list1.add(op4);

        //再创建另一个list2对象,添加一个与之前list1添加过的元素属性相同的元素,
        Operator op = new Operator(0, "second operator", "2");
        List<Operator> list2 = new ArrayList<>();
        list2.add(op);

        //从list1中删掉list2
        list1.removeAll(list2);
    }
}

其中Operator是我自定义的类。我的本意是,从从list1中删掉list2后,list1中应该只剩下两个元素:op1和op4了吧,可是结果却不是这样,而是只剩下op1了。

这是怎么回事呢?查找半天才发现,原因出在Operator类的实现上:

class Operator{
    int id;
    String msg;
    String extra;

    public Operator(int id, String msg, String extra) {
        super();
        this.id = id;
        this.msg = msg;
        this.extra = extra;
    }

    @Override
    public String toString() {
        return "Operator [id=" + id + ", msg=" + msg + ", extra=" + extra + "]";
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Operator other = (Operator) obj;
        if (id != other.id)
            return false;
        if (msg == null) {
            if (other.msg != null)
                return false;
        } else if (!msg.equals(other.msg))
            return false;
        return true;
    }

}

具体原因就是我重写了Operator类的equals()方法,而在此方法中,我只比较了Operator对象的id和msg属性,而并未比较extra属性。

而重写equals()方法和removeAll()有什么关系呢?看源码:
removeAll()的方法实现在java.util.AbstractCollection类中:

    public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(c);
        boolean modified = false;
        Iterator<?> it = iterator();
        while (it.hasNext()) {
            if (c.contains(it.next())) {
                it.remove();
                modified = true;
            }
        }
        return modified;
    }

其中调用了contains()方法,一块贴上源码:

    public boolean contains(Object o) {
        Iterator<E> it = iterator();
        if (o==null) {
            while (it.hasNext())
                if (it.next()==null)
                    return true;
        } else {
            while (it.hasNext())
                if (o.equals(it.next()))//这里调用了equals()方法
                    return true;
        }
        return false;
    }

List的removeAll()方法会最终会调用equals()方法判断需要删除哪些元素

在此例中,removeAll()传入的参数list2含有元素op,op会和list1中的元素逐个用equals()进行比较,结果,因为equals()方法不比较extra属性,因此op 和 op2, op3, op4的比较结果都是相同的,结果list1就删的只剩下了op1了。

如果把Operator类中重写的equals()方法去掉,再运行,会是什么结果呢?
去掉的话,Operator类就是Object类默认的equals()方法,会用”==”进行对象的比较,也就是比较地址。因此op和list1中的任意一个元素比较都是不相等的。结果就是,list1中不会删除任何元素。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值