Java集合之List的equals方法

一、先说结论:

1、List(ArrayList)调用equals方法,判断的是存储的元素相等,而不是直接比较引用。说明List(ArrayList)重写了equals方法

List<T> l1 = new ArrayList<>();
l1.add(T1);
List<T> l2 = new ArrayList<>();
l2.add(T1);
l1.equals(l2); //true

2、List<List< String > > res 中,可以对相同List< String>去重。直接使用res.contains(List)方法即可。

二、源码分析:

出于对ArrayList源码分析:

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

发现ArrayList实现了List接口,按理来说ArrayList需要实现所有List的接口方法。但是equals方法可以从extends的Object类获得[1]所以我误认为ArrayList的equals方法是Object类的equals方法。ArrayList中元素需比较引用。

在对复合集合res添加List时,觉得在添加新的List时,需要遍历res所有的List,然后遍历所有List元素来去重。算法复杂度就变得很高。后来尝试发现直接contains即可?

List<List<String>> res = new ArrayList<>();
List<String> l1 = new ArrayList<>();
List<String> l2 = new ArrayList<>();
l1.add("123");
l2.add("123");
res.add(l1);
System.out.println(res.contains(l2));// true

(1)首先contains方法是调用indexOf方法确定存在性。

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

(2)indexOf方法是将List中所有元素,与Object o比较。

 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++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

(3)最终还是需要将List中元素,与Object o做equals比较。(就是遍历res中的List与给定targetList进行equals比较)

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

这里调用的equals方法并不是Object类中的。ArrayList继承了AbstractList< E>,它的equals方法应该从这个抽象类中来的。发现该类确实重写了equals方法,就是使用迭代器遍历两个List每个元素是否相等。 那么ArrayList调用equals方法就是元素进行比较了。

public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof List))
            return false;

        ListIterator<E> e1 = listIterator();
        ListIterator<?> e2 = ((List<?>) o).listIterator();
        while (e1.hasNext() && e2.hasNext()) {
            E o1 = e1.next();
            Object o2 = e2.next();
            if (!(o1==null ? o2==null : o1.equals(o2)))
                return false;
        }
        return !(e1.hasNext() || e2.hasNext());
    }

因此,得出文章开头的1、2两点结论。以上~

三、补充

[1] 这里补充为啥没有显式extends Object的原因分析:
这个继承关系是是编译阶段完成的,所以我们表面上看不到。
在编译阶段,当遇到一个类没有父类的使用,编译器会指定一个默认的父类(一般为Object),当该类已经有一个父类,jvm会按照常规的方法去处理每一个类。

//原始的类,没有显式的继承Object
public class Test{
	//注意这里没有写构造方法
	public static void main(String args[]){
	
	}
}

将代码编译为class后反编译为txt文件

//编译后,如果没有父类会给你加一个默认的object父类
public class Test extends java.lang.Object{
	public Test();//编译阶段,如果没有构造方法会给你加一个空的构造方法
	public static void main(java.lang.String[]){};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值