目录

1、equals方法

2、重写equals方法的原则是什么

3、相等测试与继承

4、重写了euquals方法为什么还要重写hashcode?

5、如何写好一个equals方法(以下内容摘抄于Java 核心技术 卷1)


1、equals方法

Object 类中的 equals 方法用于检测一个对象是否等于另一个对象。Object 类中实现的 equals 方法将确定两个对象引用是否相等。看以下代码:

public static void main(String[] args) {Object o = new Object();   Object o1 = o;Object o2 = o;System.out.println(o3.equals(o2));
}

代码输出:true

这是一个合理的默认行为:如果两个对象引用相等,这两个对象就肯定相等。对于很多类来说,这已经足够了,但是还有一种情况:

class Person{ //人private String name;public Person(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}public class Test {public static void main(String[] args) {Person p1 = new Person("张三");Person p2 = new Person("张三");System.out.println(p1 == p2);System.out.println(p1.equals(p2));}
}

代码输出:false false

有时候基于业务逻辑,我们会需要比较对象内容,但此时的 equals 方法已经满足不了我们的业务要求了,所以我们才会要重写 equals 方法。

        分析: 为什么使用equals方法返回的不是true,而是和 == 相同的结果false呢。这是因为Student这个类并没有重写equals方法,当调用equals方法时,实际上调用的是Object类中的equals方法(Object 类是所有类的父类)。看看equals方法的源码:

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

所以上面的代码运行结果都是false。
        我们要想实现两个对象的状态(内容)相同,就要重写equals方法

重写Person类中的equals方法:

public boolean equals(Object o){//判断是不是同一对象,是则返回true。if(this == o) return true;//判断传进来的对象是否为null值,为null则返回false。if(o == null) return false;//判断两者类型是否相等,如果不等,返回false。if(getClass() != o.getClass()) return false;//到这一步,o 类型一致,也不为空,进行类型转换,然后才能比较。Person p = (Person)o;//此处才开始真正进行比较,return后可以&&加条件,就该类的哪些属性相等,才返回true。return name.equals(p.name);}

gatClass 方法将返回一个对象所属的类,例

A a = new A();

System.out.println(a.gatClass());  //输出A(会带包名)

此时再次运行,代码输出:false true

在子类中定义 equals 方法时,首先调用父类的 equals。如果检测失败,对象就不可能相等。如果父类中的字段都相等,就需要比较子类中的实例字段。

public class Student extends Person{private String stuId;  //学号...public boolean equals(Object o){if(!super.equals(o)) return false;//super.equals 检查 this 和 o 是否属于同一类Student student = (Student)o;return stuId.equals(student.stuId);//这个equals是用于子类同类比较,如果是子类调用子类equals与父类类型相比,会报//ClassCastException异常}
}

 2、重写equals方法的原则是什么

Java 语言规范要求 equals 方法具有小面的特性:

1.自反性:对于任何非空参考值x,x.equals(x)应该返回true。

2.对称性:对于任何非空参考值x和y,当且仅当y.equals(x)返回true时,x.equals(y)才应返回true。

3.传递性:对于x,y和z的任何

非空引用值,如果x.equals(y)返回true,而y.equals(z)返回true,则x.equals(z)应该返回true。

4.一致性:对于任何非空引用值x和y,只要未修改对象的equals比较中使用的信息,对x.equals(y)的多次调用将始终返回true或始终返回false。

5.对于任何非null参考值x,x.equals(null)应该返回false。

这些规则当然很合理。你肯定不希望类库实现者在查找数据结构中的一个元素时还要纠结调用 x.equals(y) 还是调用 y.equals(x) 的问题。

一般而言,对于一个类的两个对象,这五个原则都可以满足。看下面的代码:

 public static void main(String[] args) {Person p = null;Person p1 = new Person("张三");Person p2 = new Person("张三");Person p3 = new Person("张三");System.out.println("自反性:"+p1.equals(p1));  //trueSystem.out.println("对称性");System.out.println(p1.equals(p2));  //trueSystem.out.println(p2.equals(p1));  //trueSystem.out.println("传递性");System.out.println(p1.equals(p2));  //trueSystem.out.println(p2.equals(p3));  //trueSystem.out.println(p1.equals(p3));  //trueSystem.out.println("一致性:");//反复检测for(int i =0; i<5;i++){if(p1.equals(p2)!=p1.equals(p2)){System.out.println("没有遵守一致性");break;}}System.out.println("遵守了一致性");System.out.println("非空性");// 这里的p对象为null,所以返回falseSystem.out.println(p1.equals(p));  //false
}

输出结果:

自反性:true
对称性
false
false
传递性
false
false
false
一致性:
遵守了一致性
非空性
false

3、相等测试与继承

       如果隐式参数和显示的参数​​​​​​不属于同一个类,equals方法将如何处理?这是一个很有争议的问题。在前面的例子中,如果发现类不匹配,equals 方法返回 false。但是,许多程序员都喜欢使用 instanceof 进行检测,包括我也是。

if (!(o instanceof Person)) return false;

这样就允许了 o 属于 Person 子类时,通过。正是因为这样会导致以些麻烦,所以建议不要采用这种处理方式。看下面代码:

class Person{ //人,父类private String name;public Person(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (!(o instanceof Person)) return false;Person person = (Person) o;return Objects.equals(name, person.name);}}class Student extends Person{ // 子类//子类独有属性private String stuId;  //学号public Student(String stuId, String name) {super(name);this.stuId = stuId;}public String getStuId() {return stuId;}public void setStuId(String stuId) {this.stuId = stuId;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (!(o instanceof Student)) return false;if (!super.equals(o)) return false;Student student = (Student) o;return Objects.equals(stuId, student.stuId);}
}public class Test{public static void main(String[] args) {Person person = new Person("张三");Student student = new Student("0x111", "张三");boolean equals1 = person.equals(student);boolean equals2 = student.equals(person);System.out.println(equals1);System.out.println(equals2);}
}

代码输出:true
                  false

为什么出现了false呢,这是因为违背了对称性的原则了。分析一下也不难理解,因为student都是person,所以,per1.equals(stu2)是true,但是反过来就不成立,你不能说所有person都是student,所以stu2.equals(per1)是不成立的。这里也要明确一下父类和子类的equals方法的调用关系。在子类中定义equals方法时,首先调用父类的equals方法,如果检测失败,对象就不可能相等,如果超类中的域都相等,才需要比较子类的实例域。那么上述这个问题怎么解决呢,明白了equals方法的调用关系,那就只需在子类中的eqauls方法中添加一个判断。

// 修改student类中的equals方法
@Overridepublic boolean equals(Object o) {if (this == o) return true;//注释下面判断//if (!(o instanceof Student)) return false;//两种情况//1、o的类型不相关,在父类equals方法执行(!(o instanceof Person))返回false并取反,return false结束//2、o的类型相关//2.1、假设o为父类:先equals判断父类属性,返回true取反,执行下一步,反之return false结束//2.2、假设o为子类:先equals判断父类属性,返回true取反,执行下一步,反之return false结束if (!super.equals(o)) return false;//3、o为父类,执行下一步//3、o为子类进入if语句,进行比较子类私有的属性if (o instanceof Student){Student student = (Student) o;return Objects.equals(getName(), student.getName());}//4、子类与父类比较,只比较公共属性,相同返回true,反正falsereturn super.equals(o);

再运行以上代码:true
                             true

就符合对称性了。

还有一种情况,分为以下两种情形:

  • 如果子类可以有自己的相等性概念,则对称性需求将强制使用getClass(避免了两个不同类的 equals 比较,会执行o.getClass() != getClass()的if条件判断,如果是两种不同的类型,直接返回false,也避免了父子类 equals 方法发问题)
  • 如果由父类决定相等性概念,那么就可以使用 instanceof 检测,这样可以再不同子类的对象之间进行相等性比较

例:在学生和人的例子中,只要对应的字段相等,就认为两个对象相等,如果两个 Student 对象的学号相等,而姓名不等,就认为它们是不相同的,因此,我们要使用 getClass检测。

但是,假设使用人的身份证作为相等性检测标准,并且这个相等性概念适用于所有的子类,就可以使用 instanceof 检测,而且应该将 Person.equals 声明为 final。

4、重写了euquals方法为什么还要重写hashcode?

看到集合HashMap的底层源码的时候,自然就懂了

看看hashcode的定义:返回对象的哈希码值。支持此方法的好处是可以使用HashMap提供的散列表。

官方文档明确的说明了此方法的好处是可以使用HashMap提供的散列表。这是因为Map接口的类会使用到键对象的哈希码,当我们调用put方法时,就是根据对象的哈希码来计算存储位置的,因此必须提供对哈希码正确的保证。在java中,可以使用hashCode()这个方法来获取对象的哈希值。

public static void main(String[] args) {String s1 = "hello";String s2 = "world";System.out.println(s1.hashCode());System.out.println(s2.hashCode());
}

代码输出:99162322

113318802

可以看到不同的对象的hashcode值是不同的。

看看javaAPI的对hashcode的几点说明:

  • 在Java应用程序的执行过程中,无论何时在同一个对象上多次调用它,hashCode方法都必须一致地返回相同的整数,前提是不对对象上的equals比较中使用的信息进行修改。此整数不需要在应用程序的一次执行与同一应用程序的另一次执行之间保持一致。

  • 如果根据equals(Object)方法,两个对象是相等的,那么在每个对象上调用hashCode方法必须产生相同的整数结果。

  • 如果两个对象根据equals(java.lang.Object)方法是不相等的,那么在每个对象上调用hashCode方法必须产生不同的整数结果,这是不需要的。但是,程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。

    回到我们前面的问题,为什么重写equals方法,必须要重写hashcode方法。在Object类中,hashCode方法是通过Object对象的地址计算出来的,因为Object对象只与自身相等,所以同一个对象的地址总是相等的,计算取得的哈希码也必然相等。对于不同的对象,由于地址不同,所获取的哈希码自然也不会相等。所以如果一个类重写了equals方法,但没有重写hashCode方法,将会直接违法了第2条规定。还有一点就是重写hashcode()方法,可以方便用户将对象插入到散列表中。

5、如何写好一个equals方法(以下内容摘抄于Java 核心技术 卷1)

1. 显式参数命名为otherObject,稍后需要将它转换成另一个叫做other的变量。

2. 检测this与otherObject是否引用同一个对象:if(this=otherObject)returntrue;这条语句只是一个优化。实际上,这是一种经常采用的形式。因为计算这个等式要比一个一个地比较类中的域所付出的代价小得多。

3. 检测otherObject是否为null,如果为null,返回false。这项检测是很必要的。if(otherObject=null)returnfalse;

4. 比较this与otherObject是否属于同一个类。如果equals的语义在每个子类中有所改变,就使用getClass检测:if(getClass()!=otherObject.getCIassO)returnfalse;如果所有的子类都拥有统一的语义,就使用instanceof检测:if(!(otherObjectinstanceofClassName))returnfalse;

5. 将otherObject转换为相应的类类型变量:ClassNameother=(ClassName)otherObject

6. 现在开始对所有需要比较的域进行比较了。使用=比较基本类型域,使用equals比较对象域。如果所有的域都匹配,就返回true;否则返回false。

return  fieldl  ==  other.field

&& Objects.equals ( field2 , other.field2)

&& . . .;

7. 如果在子类中重新定义equals,就要在其中包含调用super.equals(other)。

如果你用的是eclipse或者是idea集成环境的话,可以使用快捷键自动生成符合以上标准的equals()方法,但是有时候需要自定义,所以知道原理很重要。

(内容模板有借鉴于博客园一文章,第一次创作,支持一下)

equals方法详解相关推荐

  1. java equals方法详解

    序言:准备总结一些java基础的知识方便以后查阅,从equals入手 目录: 等于(==)详解 equals方法详解 一.等于(==)详解 先明确一点:"==" 其实是存储地址的比 ...

  2. object类中的equals与自定义equals方法详解

    object类中的equals与自定义equal方法详解 1.this怎么理解?this == obj表示什么? this就是当前你new出来的对象,这里指谁调用equal方法this指的就是谁,ob ...

  3. equals()方法详解

    Java语言中equals()方法的使用可以说比较的频繁,但是如果轻视equals()方法,一些意想不到的错误就会产生.哈哈,说的有点严重了~ 先谈谈equals()方法的出身.equals()方法在 ...

  4. java.equal例子_Java中的== 和equals()方法详解与实例

    Java中的== 和equals()方法: Java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型. byte,short,char,int,long,float,double,boo ...

  5. java equ,Java equals方法详解

    首先equals方法是object类的方法,所有的类都默认继承object类,object类也就是所有类的超类. 如果两个对象进行相等比较,需要调用x.equals(y),但是如果没有重写equals ...

  6. Object类中hashCode()和equals()方法详解(附图)

    下图是规范中要求的: 图解:比如equals相等的箭头指向hashcode相等,标示equals相等那么必有hashcode相等.另外有两个箭头指向别人的标示可能是其中之一. //JAVA代码: pu ...

  7. equals ( ) 方法详解

    Object类的equals( )方法 equals()是Object类中的一个方法,用于判断引用类型 equals 和 == 的区别是 == ==是一个比较运算符,可以用来判断基本类型的值是否相等, ...

  8. 【Java】equals() 方法详解

    目录 equals 方法 equals方法重写 equals方法重写规则 equals方法比较String类型 Object 类中的 equals 方法用于检测一个对象是否等于另外一个对象 equal ...

  9. Java equals 方法详解

    equals()方法: 是一个方法,而非运算符 只能适用于引用数据类型 Object类中equls()的定义: public boolean equals(Object obj) {return (t ...

最新文章

  1. 2022年想成为软件测试工程师,这个学习路线收藏起来
  2. 断网与黑客无关 我来抖一抖暴风那点见不得人的猫腻
  3. 17. javacript高级程序设计-错误处理与调试
  4. 学习笔记——使用下划线命名的规则
  5. java xml 文件_Java 对xml文件的读写操作
  6. github使用-知乎的某小姐的一篇文章
  7. openssl漏洞怎么处理_以太坊UDP流量放大反射DDOS漏洞
  8. 2016-6-28 工作总结
  9. 和商简智能CEO关于APS的聊后感
  10. 通信原理matlab版,通信原理matlab
  11. CAN数据格式-ASC
  12. 如何提取仙剑奇侠传4的模型
  13. Terrasolid安装
  14. i春秋Web渗透测试工程师(初级)学习笔记(第三章)
  15. Games102_lecture8几何建模与处理基础_离散微分几何,Utopia框架介绍
  16. 懒人神器,IDEA插件之EasyCode,自动生成CRUD代码
  17. 电脑白屏,电脑白屏是怎么回事?是系统的原因还是
  18. javascript的基本概念
  19. react前端项目_如何使用React前端设置Ruby on Rails项目
  20. ISA SERVER常见问题总结专用贴(转)

热门文章

  1. 腾讯云小直播demo配置流程
  2. 职场基本功,如何让你的讲话更有条理?
  3. 新浪微博账号运营小技巧,800媒体助手让你轻松成为微博达人
  4. python新手入门指导_python新手入门指导
  5. 15.系统限制和选项
  6. linux 下文件批量重命名
  7. 学习动漫插画的网络班排行榜
  8. Response响应的中文乱码问题
  9. html页面设置成中文编码(UTF-8)
  10. 面试题 | 设计youtube