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)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM