List中的Contains

本文探讨了在实现通讯录导入功能时遇到的重复数据问题。通过对List的contains方法进行深入分析,指出了其默认行为在自定义对象比较时存在的缺陷,并提供了具体的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

感谢

文章是我按照我的bug和debug过程写的,这里感谢这篇文章的帮助:http://www.2cto.com/kf/201506/410713.html

背景

最近在弄一个通讯录导入小功能:【A操作】读取通讯录-获得列表-选择你想要的某些联系人-保存到安卓客户端。
但是遇到个问题:当你导入成功后,【B操作】想再导入几个联系人的时候。再走一遍上述流程,你会发现,通讯录和你本地有重复的数据

那么问题来了:通讯录是一个列表, 客户端本地也有一个列表。我们需要把通讯录读取后,移除我们本地的数据。展示出来的全是未导入的数据

案例

contains 1

说到一个List里包含某个*, 会不会想到Contains?最常见的是这样的:

public void main1(){
    ArrayList<String> list = new ArrayList<>();
    list.add("张三");
    list.add("李四");
    list.add("王二麻子");
    String aimString1 = "李四";
    String aimString2 = "我不是黄蓉";
    if(list.contains(aimString1)) {
        Log.i("是否包含?", "包含了-李四");
    }
    Log.i("是否包含?", "包含了-我不是黄蓉?"+list.contains(aimString2));

}

打印如下:

I/是否包含?﹕ 包含了-李四
I/是否包含?﹕ 包含了-我不是黄蓉?false

可以看到Contains很完美的实现了我们的目标!你以为这样这篇文章就结束了?NoNoNo ~

contains 2

如果我们要比对的不是String类型,而是一个下面的自定义类呢?

public class userInfo {
    private int _id ;
    private String name ;
    private String phone ;

    public userInfo(String name){
        this.name = name ;
    }

    // getter和setter略去
}

测试代码小改动了下,如下:

public void main2() {
    ArrayList<userInfo> list = new ArrayList<>();
    list.add(new userInfo("张三"));
    list.add(new userInfo("李四"));
    list.add(new userInfo("王二麻子"));
    userInfo aimUser1 = new userInfo("李四");
    if (list.contains(aimUser1)) {
        Log.i("是否包含?", "包含了-李四");
    } else {
        Log.i("是否包含?", "我擦,居然没包含?不科学啊");
    }

}

打印如下:

I/是否包含?﹕ 我擦,居然没包含?不科学啊

contains 进阶


有问题就找嘛,我们按住Ctrl点击contains来看源码:

@Override public boolean contains(Object object) {
    Object[] a = array;
    int s = size;
    if (object != null) {
        for (int i = 0; i < s; i++) {
            if (object.equals(a[i])) {
                return true;
            }
        }
    } else {
        for (int i = 0; i < s; i++) {
            if (a[i] == null) {
                return true;
            }
        }
    }
    return false;
}

PS:系统有啥叼的嘛, 还不是用for循环挨个对比的

里面用到了

object.equals(a[i])

其源码是

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

其实这里面的Object就是我们上面的自定义类userInfo 这上面的源码居然用 this==o 来对比两个实体?这就是判断两者的地址是否相等嘛。
可是我们需要的是两者的内容相等

按照文章开头那里感谢的那篇文章,在我们的实体类中重写equals方法,没啥难的,我们一起来看:

public class userInfo {
    private int _id ;
    private String name ;
    private String phone ;

    public userInfo(String name){
        this.name = name ;
    }

    // getter和setter略去

    @Override
    public boolean equals(Object o) {
        if(o instanceof userInfo) {
            // 类型强转
            userInfo _userInfo = (userInfo) o ;
    //          // 仅仅比对name
    //          return this.name.equals(_userInfo.getName()) ;
            // 比对三个参数
            return this.name.equals(_userInfo.getName()) &&
                    this.phone.equals(_userInfo.getPhone()) &&
                    this._id == _userInfo.get_id();
        }
        return super.equals(o);
    }
}

这时候再跑一次code ,崩~ NullPointerException

String crash = null ;
Log.i("log", "result:"+crash.equals("oh no !"));

equals前面是不能为null的。那怎么办? 我怎么知道。。。 尽量避免不让其为null呗,或者你加判断试试?顺便说一句,下面的写法比较好:

String crash = null ;
Log.i("log", "result:"+"oh no !".equals(crash));

实战

一开始就说到是一个导入通讯录的小任务嘛,上面一直是举例子,这下轮到实战了。不过我不想写了。任性一回 。

疑问

我一直想知道 List中我通过contains得知了是否包含,但是位置怎么获取呢?

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值