详解List存储引用类型时需要复写 .equels()的原因

先来看下面一个例子:先定义了一个简单的POJO类,然后实例化了一个ArrayList存储Student对象

import java.util.ArrayList;
import java.util.List;

class Student{
	public int id;
	public String name;
	public Student(int id,String name) {
		this.id=id;
		this.name=name;
	}
	@Override
	public String toString() {
		return "id : " + id + "   name : " + name;
	}
}


public class TestCollection {
	public static void main(String[] args) {
		List<Student> stu = new ArrayList<>();
		stu.add(new Student(1, "andy"));
		stu.add(new Student(2, "john"));
		stu.add(new Student(3, "jack"));
	}
}

进行如下操作:

		Student black=new Student(4, "black");
		stu.add(black);
		System.out.println(stu.contains(black));//判断stu中是否包含black对象

打印结果:true 

没有问题

再进行如下操作:

		System.out.println(stu.contains(new Student(3, "jack")));

打印结果:false

打印出来为flase,但是我们的stu中确实有{ id=3,name="jack"}的对象,仔细一想也没什么问题,new Student(3, "jack") 创建的是一个{ id=3,name="jack"}的匿名对象,前面stu.add(new Student(3, "jack")) 和stu.contains(new Student(3, "jack"))中的{ id=3,name="jack"}本来就不是同一块地址空间,显然这不是我们想看到的

再进行如下操作

		stu.remove(new Student(1,"andy"));
		System.out.println(stu.get(0));

打印结果:id : 1   name : andy

显然没有将第一个信息删除,至于原因和上面是相似的,那么怎么解决这个问题呢?

如果List需要存储引用类型,并且使用到 .remove() , contains() 等方法,则需要该引用类型复写   .equals() 方法。

以下为复写 .equals()  的完整Student 实例

import java.util.ArrayList;
import java.util.List;

class Student {
	public int id;
	public String name;

	public Student(int id, String name) {
		this.id = id;
		this.name = name;
	}

	@Override
	public String toString() {
		return "id : " + id + "   name : " + name;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;//如果传进来的对象就是当前对象就直接返回true
		}
		if (obj instanceof Student) {
			Student stu = (Student) obj;
			if (this.id == stu.id) {
				if (this.name.equals(stu.name)) {
					return true;
				}
				return false;
			}
			return false;
		}
		return false;
	}

}

public class TestCollection {
	public static void main(String[] args) {
		List<Student> stu = new ArrayList<>();
		stu.add(new Student(1, "andy"));
		stu.add(new Student(2, "john"));
		stu.add(new Student(3, "jack"));
		Student black = new Student(4, "black");
		stu.add(black);
		System.out.println("stu是否包含这个对象:"+stu.contains(new Student(3, "jack")));
		stu.remove(new Student(1, "andy"));
		System.out.println(stu.get(0));//id=1 的 andy 被成功删除
	}
}

打印结果:

stu是否包含这个对象:true
id : 2   name : john

这正是我们想看到的结果,下面来探究一下,为什么会这样。

首先打开ArrayList中的  .remove()  相关源码:

首先他传入了一个Object 对象,在我们这个程序中,传入的对象为:new Student(1, "andy"),

o !=null;  程序跳转到551行

552行:for循环遍历这个集合中的数据

553行:有一个判断条件 o.equals(elementData[index]  ;

正是调用了我们复写的 .equals(); 当  .equals()返回true时则将集合中的这个数据删除。

再打开ArrayList中的  .contains()  相关源码:

可以看到,他在判断这个对象是否存在于这个集合中时,都会调用 .equals()方法。

 

那么为什么会出现这个现象呢?

 

不难理解:Java中,任何类都继承了Object方法,而 .equals() 方法最初被定义在Object中,当你没有复写他时,会自动调用Object中的  .equals() 。

那么我们打开Object中的  .equals():

非常简单:只要不是这个对象,就返回false。前面的打印结果就很好理解了。

 

我们来总结一下:当你调用 集合类中的 .remove(o) 方法会经历怎样一个过程,当这个对象不为空的时候,他会用一个for循环遍历整个集合,再调用o.equals()与集合中每个元素进行比较。如果  .equals() 被复写了,就会调用这个类中的.equals(),如果没有复写,就会调用Object中的 .equals()。当.equals() 返回true时,就将集合中的这个元素删除。

以下方法也会调用到 .equals();

 

在LinkedList 和 Vector 中的相关方法,也会调用  .equals(),  因此List需要存储引用类型,并且使用到 .remove() , contains() 等方法,则需要该引用类型复写   .equals() 方法。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值