List的remove方法里的坑

Posted wuxun1997

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了List的remove方法里的坑相关的知识,希望对你有一定的参考价值。

  今天遇到一件怪事,用一个ArrayList添加了一个对象,再调用ArrayList的remove方法删除该对象,当然这时对象是数据库里查出来的,但内容绝对是一样,却发现remove失败了。演示一下,这里用了自定义的Merchant对象,测试时只需随便自定义一个对象即可:

  

  public static void main(String[] args) {
        List<Merchant> merchants = new ArrayList<>();
        Merchant merchant = new Merchant();
        merchant.setMerchantId("aa");
        merchant.setMarketPlaceId("bb");
        merchant.setSecretKey("aa");
        merchant.setAccessKeyId("bb");
        merchants.add(merchant);
        Merchant other = new Merchant();
        other.setMerchantId("aa");
        other.setMarketPlaceId("bb");
        other.setSecretKey("aa");
        other.setAccessKeyId("bb");

        boolean isRemoved = merchants.remove(other);

        System.out.println(isRemoved);
    }

  结果打印出来是false。然后去看了一下ArrayList的remove方法:

    public boolean remove(Object var1) {
        int var2;
        if (var1 == null) {
            for(var2 = 0; var2 < this.size; ++var2) {
                if (this.elementData[var2] == null) {
                    this.fastRemove(var2);
                    return true;
                }
            }
        } else {
            for(var2 = 0; var2 < this.size; ++var2) {
                if (var1.equals(this.elementData[var2])) {
                    this.fastRemove(var2);
                    return true;
                }
            }
        }

        return false;
    }

    private void fastRemove(int var1) {
        ++this.modCount;
        int var2 = this.size - var1 - 1;
        if (var2 > 0) {
            System.arraycopy(this.elementData, var1 + 1, this.elementData, var1, var2);
        }

        this.elementData[--this.size] = null;
    }

   关键在标黄那一行,remove的前提是两个对象的equals方法必须相等,而我定义的Merchant对象并无复写Object类的equals方法,那么执行到这一行时equals就是Object的equals方法:

    public boolean equals(Object obj) {
        return (this == obj);
    }

  是否一下子有种恍然大悟的被坑的感觉?反正我是这样子觉得的,Object类比较的是引用,而main里测试的是两个不同的引用,equals必然是false,remove自然也是false了,不信可以把equals也一并打印一下:

    public static void main(String[] args) {
        List<Merchant> merchants = new ArrayList<>();
        Merchant merchant = new Merchant();
        merchant.setMerchantId("aa");
        merchant.setMarketPlaceId("bb");
        merchant.setSecretKey("aa");
        merchant.setAccessKeyId("bb");
        merchants.add(merchant);
        Merchant other = new Merchant();
        other.setMerchantId("aa");
        other.setMarketPlaceId("bb");
        other.setSecretKey("aa");
        other.setAccessKeyId("bb");

        boolean isRemoved = merchants.remove(other);

        System.out.println(other.equals(merchant));
        System.out.println(isRemoved);
    }

  你会发现两个false出现了。那么咋办呢?很简单,既然是equals引起的,那就让它来解决问题,我们再Merchant里重写Object的equals即可。当然既然重写了equals,我们也得把hashCode方法也一起重写一下,现在的IDE都很智能,自动生成即可。等你的自定义类生成好了这俩方法后,重新执行上面这个main,你会发现出现俩true了。

  当然,如果你希望在自定义的对象里修改了非关键属性(比如上面的Merchant里的accessKeyId、secretKey等这些属性,在数据库update他们的值之后就都改变了)都不影响该对象的唯一性,那么我们可以把equals和hashCode方法里自动生成的其他属性去掉,只保留能识别该对象的关键属性(比如merchantId)。

以上是关于List的remove方法里的坑的主要内容,如果未能解决你的问题,请参考以下文章

为什么Java里的Arrays.asList不能用add和remove方法?

Arrays.asList中所遇到的坑

为啥Java里的Arrays.asList不能用add和remove方法

201621044079 韩烨作业09-集合与泛型

Java中list在循环中删除元素的坑

列表常用方法