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

原文地址:https://www.cnblogs.com/wuxun1997/p/10887511.html

时间: 2024-10-10 03:20:49

List的remove方法里的坑的相关文章

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

在平时的开发过程中,我们知道可以将一个Array的对象转化为List.这样的操作,我们只要采用Arrays.asList这个方法就行了.笔者前段时间一直用这个方法,有一天,我发现通过Arrays.asList得到的List无法进行add和remove等操作. 下面是一段很简单的测试代码: public class MainFacade { public static void main(String[] args) { List<Integer> list = Arrays.asList(1,

list的remove方法

list有两个remove方法: E remove(int index);//根据索引删除 boolean remove(Object o);//根据对象删除 List<String> list = new ArrayList<String>(); String a = "1"; String b = "2"; String c = "2"; String d = "1"; String e = &qu

C# Datatable删除行的Delete和Remove方法

delete和remove Delete的使用是 datatable.Rows[i].Delete(); Remove的使用是datatable.Rows.Remove(datatable.Rows[i]); 这两个的区别是,使用delete后,只是该行被标记为deleted,但是还存在,用Rows.Count来获取行数时,还是删除之前的行数.需要使用datatable.AcceptChanges()方法来提交修改. 而Remove方法则是直接删除. 如果在for循环里删除行的话,最好是使用de

Datatable删除行的Delete和Remove方法介绍

在实际项目开发中,如果要删除DataTable中的某一行,大约有以下几种办法: 使用DataTable.Rows.Remove(DataRow),或者DataTable.Rows.RemoveAt(index):可以直接删除行 datatable.Rows.Delete().Delete()之后需要datatable.AccepteChanges()方法确认完全删除,因为Delete()只是将相应列的状态标志为删除,还可以通过datatable.RejectChanges()回滚,使该行取消删除

Java连载85-集合的Contains和Remove方法

一.包含与删除两种方法解析 1.boolean contains(Object o);判断集合中是否包含某个元素. package com.bjpowernode.java_learning; import java.util.*; ? public class D85_1_ContainsMethod { public static void main(String[] args) { //创建集合 Collection c = new ArrayList(); //创建两个Integer类型

蒋步星:报表&数据分析平台里的坑

报表平台(或BI.数据分析平台)是指提供报表.统计图及其它BI组件(仪表盘.数据看板.分析报告等)的组织管理.权限控制.调度生成.发布订阅等功能的软件系统,让业务用户能随时随地地访问全企业的报表和数据.这是近五六年来报表和BI领域的一个热门需求,在基本业务系统建设较完善后,许多用户都希望把各系统中的报表和数据分析功能打通后统一管理. 在业界混久了,经常还能听到客户在实际用过某个报表工具后表扬该产品的话(当然骂声可能更多),但是用过之后还表扬某个报表或数据分析平台的话却几乎从没听说过!对于这类平台

[iOS]为什么不要在init初始化方法里调用self.view

首先.如果你调用self.view的时候,就会调用view的getter方法, 这个时候,view是空的,那么系统就会自动给你创建一个view,然后就会触发ViewDidLoad方法.那么这个时候,如果你init方法里有数组初始化.但是你还没走到那步,而直接就给数组赋值了,那么这个值赋值给了一个不存在的数组.这样就容易出现错误.所以,尽量不要在init方法里写可视化控件的语句. 附1: UIViewController的生命周期: 当一个视图控制器被创建,并在屏幕上显示的时候. 代码的执行顺序1

Iterator的remove方法可保证从源集合中安全地删除对象(转)

import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class IteratorTest{ public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("Test1"); list.add("Test2&qu

EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解

EntityFramework Core 1.1方法理论详解 当我们利用EF Core查询数据库时如果我们不显式关闭变更追踪的话,此时实体是被追踪的,关于变更追踪我们下节再叙.就像我们之前在EF 6.x中讨论的那样,不建议手动关闭变更追踪,对于有些特殊情况下,关闭变更追踪可能会导致许多问题的发生. 实体状态 对于EF Core 1.1中依然有四种状态,有的人说不是有五种状态么,UnChanged.Added.Modified.Deleted.Detached.如果我们按照变更追踪来划分的话,实际