代码编织梦想

文章摘抄自http://blog.csdn.net/javazejian/article/details/51348320

我们先来看看contains方法内部实现

@Override
public boolean contains(Object o) {
return indexOf(o) != -1;
}
进入indexof方法

@Override
public int indexOf(Object o) {
E[] a = this.a;
//当o是null的时候也会返回集合中null的位置
if (o == null) {
for (int i = 0; i < a.length; i++)
if (a[i] == null)
return i;
} else {
//indexOf(),实际调用的是传入的contains(Object o)的实参的equals方法
for (int i = 0; i < a.length; i++)
if (o.equals(a[i]))
return i;
}
return -1;
一般情况下我们没有重写equals()方法,这时就会调用继承自object类的equals()方法,而我们都知道object的equals()方法,实际就是 ==,如下

public boolean equals(Object obj) {
return (this == obj);
}
比较的是是否为同一个对象。所以再调用contains()方法时,实际就是看是否是同一个对象,但是如果重写了contains(Object o)中形参的equals()方法,那么就会产生不同的效果。

而大家都知道,如果重写equals方法,就必须要遵循以下规则:

自反性。对于任何非null的引用值x,x.equals(x)应返回true。

对称性。对于任何非null的引用值x与y,当且仅当:y.equals(x)返回true时,x.equals(y)才返回true。

传递性。对于任何非null的引用值x、y与z,如果y.equals(x)返回true,y.equals(z)返回true,那么x.equals(z)也应返回true。

一致性。对于任何非null的引用值x与y,假设对象上equals比较中的信息没有被修改,则多次调用x.equals(y)始终返回true或者始终返回false。

对于任何非空引用值x,x.equal(null)应返回false。

下面举个例子:

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

public class AbnormalResult {
public static void main(String[] args) {
List list = new ArrayList();
A a = new A();
B b = new B();
list.add(a);
System.out.println(“list.contains(a)->” + list.contains(a));
System.out.println(“list.contains(b)->” + list.contains(b));
list.clear();
list.add(b);
System.out.println(“list.contains(a)->” + list.contains(a));
System.out.println(“list.contains(b)->” + list.contains(b));
}
//我们通过静态内部类来精简代码,可以看到我们都重写了List中插入元素的equals方法,这样在调用contains方法时,就会按照我们的equals方法进行操作
static class A {
@Override
public boolean equals(Object obj) {
return obj instanceof A;
}
}
static class B extends A {
@Override
public boolean equals(Object obj) {
return obj instanceof B;
}
}
}
我们可以看到输出结果为:

list.contains(a)->true

list.contains(b)->false

list.contains(a)->true

list.contains(b)->true

表面上看来这样没有问题,但是如果我们只观察这个equals方法就会发现,它违反了重写equals()方法的对称性原则,因为上面调用的四次contains()方法,实际调用的equals()方法如下所示:

①a.equals(a)->true;//因为我们只插入了一个元素,所以就是在跟插入的这个元素比较,下同

②b.equals(a)->false;

③a.equals(b)->true;

④b.equals(b)->true;

可以看到②③的比较的结果是不同的,这就违反了对称性原则。所以,当你打算重写contains()方法的equals()规则时,一定要检查清楚,是否符合以上原则,验证后再进行使用。

上面的代码改为如下,就会都返回true

static class B extends A{
@Override
public boolean equals(Object obj) {
if(obj instanceof B){
return true;
}
return super.equals(obj);
}
}
但实际上这种方法又会违背传递性原则,比如下面一个例子

//父类
public class Person {
protected String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person(String name){
this.name = name;
}
public boolean equals(Object object){
if(object instanceof Person){
Person p = (Person) object;
if(p.getName() == null || name == null){
return false;
}
else{
return name.equalsIgnoreCase(p.getName ());
}
}
return false;
}
}
//子类
public class Employee extends Person{
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Employee(String name,int id){
super(name);
this.id = id;
}
/**
* 重写equals()方法
*/
public boolean equals(Object object){
if(object instanceof Employee){
Employee e = (Employee) object;
return super.equals(object) && e.getId() == id;
}
return super.equals(object);
}
//测试代码
public class Test {
public static void main(String[] args) {
Employee e1 = new Employee(“chenssy”, 23);
Employee e2 = new Employee(“chenssy”, 24);
Person p1 = new Person(“chenssy”);
System.out.println(p1.equals(e1));
System.out.println(p1.equals(e2));
System.out.println(e1.equals(e2));
}
}
根据传递性原则,e1.equals(e2)也应该返回true,但实际结果是false,对于那 e1!=e2 我们非常容易理解,因为他们不仅需要比较 name,还需要比较 ID。但是 p1 即等于 e1 也等于 e2,这是非常奇怪的,因为 e1、e2 明明是两个不同的类,但为什么会出现这个情况?首先 p1.equals(e1),是调用 p1 的 equals 方法,该方法使用 instanceof 关键字来检查 e1 是否为 Person 类,这里我们再看看 instanceof:判断其左边对象是否为其右边类的实例,也可以用来判断继承中的子类的实例是否为父类的实现。他们两者存在继承关系,肯定会返回 true 了,而两者 name 又相同,所以结果肯定是 true。所以出现上面的情况就是使用了关键字 instanceof,这是非常容易导致我们“钻牛角尖”。故在覆写 equals 时推荐使用 getClass 进行类型判断。而不是使用 instanceof(除非子类拥有统一的语义)

因为getclass()方法判断的是是否为同一个类,而instanceof()判断是否有继承关系,如果上面equals(),里面的instanceof()换成object.getClass()==Employee.class,就不会出现上述问题,因为都返回false。

作者:shenqueying
来源:CSDN
原文:https://blog.csdn.net/shenqueying/article/details/80073140
版权声明:本文为博主原创文章,转载请附上博文链接!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/sjn0815/article/details/91956269

集合中的contains方法怎么去实现,以及怎么重写对象的equals方法?_yuanboqi的博客-爱代码爱编程

//创建一个ArrayList集合      ArrayList集合继承List接口,值可重复,有序 ArrayList arrayList=new ArrayList(); arrayList.add("dog"); arrayList.add("dog"); arrayList.add("dog");                    a

关于hashset的使用,以及contains的重写问题。_时间里的河的博客-爱代码爱编程

1. set的定义: private Set<Doc> aSet = new HashSet<>(); 2.由于set的contains(Object)函数,只能是对于有相同变量地址的对象返回TURE。否则就返回false。 考虑下面的情况,如果set中已经有一个aDOC的对象,现在new 一个新的aDoc的数据成员和aDOC完全

list contains比较对象需要注意的地方_不浪漫的罪名ly的博客-爱代码爱编程_listcontains方法比较对象

List contains()比较对象,需要重写对象的equals()和hashCode()方法。 package com.kanzhun.phoenix.admin.mytest; import java.util.A

java中list.contains()方法,要重写equals(),hashcode()方法_weixin_40599844的博客-爱代码爱编程_java list.contains

  今天动力节点java培训机构小编为大家介绍“JAVA中list.contains()方法,要重写equals(),hashcode()方法”,希望能够帮助正在学习java的零基础学员,下面就随小编一起看看吧。   object对象中的 public boolean equals(Object obj),对于任何非空引用值 x 和 y,当且仅当 x

java中list集合中contains()的用法,啥意思-爱代码爱编程

1、java中list集合中contains()的用法为: public boolean list.contains(Object o) 意思为:当前列表若包含某元素,返回结果为true, 若不包含该元素,返回结果为fa

List中的contains()方法,判断list中对象是否相等,需要重写对象的equals()方法-爱代码爱编程

实体类重写equals()方法 package com.rpmc.demo.protoEntity.tsrm.section; import java.util.Objects; public class TsrSection { private int lineId;//线路id private int sectionId;//区

【知识点】String是如何重写equals方法,比较对象的内容的?-爱代码爱编程

public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if

java 重写equals_Java 基础 - 如何重写equals()-爱代码爱编程

常见equals方法实现错误 1-未使用@override对覆盖超类的方法进行标记. public class Employee { public boolean equals(Employee other) { return Objects.equals(name, other.name) && salary ==othe

java List实体类的比较,contains和equals,无需重写点击即用-爱代码爱编程

业务需求,有时候我们会需要比较当前的实体类的值是否和数据库查出来的某一条数据相同。 最初我以为直接用List.contains就可以比较,但是!俺们实际操作一下。 // 介是实体类 public class Employee { private Integer id; private String name; private String g

java中的==和equals详解-爱代码爱编程

1. equals equals比较的时候如果是引用类型(除了String类型),那么使用的是object中的equals方法,比较的是地址是否一样; 如果是String类型的对象,那么String类重写了Object中的equals方法,首先比较地址是否一样,一样的话返回true,不一样再比较是否是为同种类型,不是同类型就返回false,同类型之后再看

Java List的contains()方法详解以及重写equals()方法时需要注意的地方-爱代码爱编程

contains方法内部实现 @Override public boolean contains(Object o) { return indexOf(o) != -1; indexof方法内部实现 @Override public int indexOf(Object o) { E[] a = t

contains方法,及重写equals&hashcode_stream 的 contains 重写方法把部分相等变成完全相等-爱代码爱编程

一开始我以为,contains方法的比较是基于==的,也就是说,假设我有一个Set<String>,里面有一个"zzj"的String对象,如果我要判断"zzj"在不在这里面,实际上是做不到的,只能判断这个对象在不在这里面,但是后来无意中看到了他的规约,我发现他的等于是调用的equals方法(虽然对于Object,equals就是==),所以如

java重写equals时集合contains问题_重写equal方法 list.contains-爱代码爱编程

问题   在父类中重写了equals方法,将父类对象添加进list中并且不存在子类对象时,调用list.contains(子类)返回true,反之亦然。 结论 重写equals时要考虑以下原则: 自反性:非空引用