Android&Java List与equals的微妙关系,小心掉坑里

46 篇文章 2 订阅
9 篇文章 0 订阅

前言

List 有多个实现,本文以ArrayList(LinkedList也一样)作为说明,equals是Object的一个成员函数,例子中的bean重写实现它。

一、Bean 类定义并重写equals函数

public class Book {
    private String id;
    private String name;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object obj) {
        //这里重写
        if (obj instanceof Book) {
            //obj是book对象,使用当前对象id与obj的id进行对比
            return id == null ? false : id.equals(((Book) obj).id);
        } else if (obj instanceof String) {
            //目的可以接受id进来匹配是不是同一本书(我们得到id,不需要构造一个book对象来进行匹配对比)
            return obj.equals(id);
        }
        return false;
    }
}

二、equals的演练

  1. Bean 对象 vs Bean对象
public static void main(String[] args) {
        Book book1 = new Book();
        book1.setId("111");
        book1.setName("语文");

        Book book2 = new Book();
        book2.setId("222");
        book2.setName("数学");

        println("book1 equals book2 ? " + book1.equals(book2));
}

book1 equals book2 ? false

book2作为参数,book1对象调用equals函数,id不一样,结果自然是false。

  1. Bean对象 vs String 对象
public static void main(String[] args) {
        String id = "111";
        Book book1 = new Book();
        book1.setId(id);
        book1.setName("语文");
        println("book1 equals String ? " + book1.equals("111"));
}

book1 equals String ? true

字符串"111"作为参数,book1对象调用equals函数,结果是true。这也符合我们重写equals的目的。

List演练

我们知道,list中包含某个对象,是通过遍历list的每一个元素和给定的对象相匹配,如果匹配上说明包含,反之不包含,且匹配也是调用equals函数。
看如下代码:

 public static void main(String[] args) {
        String id = "111";
        Book book1 = new Book();
        book1.setId(id);
        book1.setName("语文");

        Book book2 = new Book();
        book2.setId("222");
        book2.setName("数学");

        ArrayList list = new ArrayList(2);
        list.add(book1);
        list.add(book2);

        println("list contains book1 ? " + list.contains(book1));
        println("list contains id 111 ? " + list.contains("111"));
}

执行结果:

list contains book1 ? true
list contains id 111 ? false

结果不是我们期望的,前面已经验证 book1.equals(“111”)的结果是true,list.contains(“111”)的结果是false。
不急,来看看ArrayList的contains实现(contains实际上是调用了indexOf函数):

 public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

    /**
     * Returns the index of the first occurrence of the specified element
     * in this list, or -1 if this list does not contain the element.
     * More formally, returns the lowest index <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
     * or -1 if there is no such index.
     */
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
            //因为这个判断用的是o.equals,所以不包含111
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

for (int i = 0; i < size; i++)确实是遍历了所有元素。问题在于if (o.equals(elementData[i]))
这里调用的是参数对象的equals,不是调用元素对象的equals函数。如果反过来if (elementData[i].equals(o))那么我们上面的结果就是true。

通俗的讲,list.contains(“111”),contains函数中匹配时,是"111".equals(elementData[i]),不再是book.equals(“111”)。

总体来说,我们有重新实现equals的情况下,在使用list的时候要避免使用非本类的对象匹配方式,一定要同类如:list.contains(book1)。上面的情况请用111 构造出一个Book对象才能得到正确的结果。当然,list的indexOf也是如此。

那么代码上为什么有这样的坑呢,应该为了代码简练,如果写成elementData[i].equals(o)的话,elementData[i]需要进行判空。
有知道更多原因的请留言,抱拳谢过。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值