尽管Object是一个具体类,但是设计它主要是为了扩展。它所有的非final方法(equals、hashCode、toString、clone和finalize)都有明确的通用约定,因为它们被设计成是要被覆盖的。
任何一个类,它在覆盖这些方法的时候,都有责任遵守这些通用约定;如果不能做到这一点,其他依赖于这些约定的类(例如:HashMap和HashSet)就无法结合该类一起正常工作。
有一种"值类"不需要覆盖equals方法,即实例受控确保"每个值至多只存在一个对象"的类。枚举类型就属于这种类。
对于这样的类而言,逻辑相同与对象等同是一回事,因此Object的equals方法等同于逻辑意义上的equals方法。
如果类具有自己特有的“逻辑相等”概念(不同于对象等同的概念),而且超类还没有覆盖equals以实现期望的行为,这时我们需要覆盖equals方法。
这通常属于“值类(value class)”的情形。值类仅仅是一个表示值的类,例如Integer或者Date。
程序员在利用equals方法来比较对象的引用时,希望知道它们在逻辑上是否相等,而不是想了解它们是否指向同一个对象。
为了满足程序员的要求,不仅必须重写equals方法,而且这样做也使得这个类的实例可以被用作映射表的键,或者集合的元素,使映射和集合表现出预期的行为。
什么时候应该覆盖Object.equals
如果类具有自己特有的”逻辑相等“概念(不同于对象等同的概念),而且超类还没有覆盖equals以实现期望的行为。
在覆盖equals方法的时候,你必须要遵守它的通用约定(自反性、对称性、传递性、一致性)。
为什么一定要遵守通用约定,因为其他的程序设计都认为你遵循了通用约定,例如其他程序认为:x.equals(y)跟y.equals(x)是一样的。
如果你没有遵循,其他的程序代码就会有问题。
list.contains(s);
在覆盖equals方法的时候,必须遵守它的通用约定。
equals方法实现了等价关系
自反性:对于任何非null的引用值x,x.equals(x)必须返回true。
对称性:对于任何非null的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)必须返回true。
传递性:对于任何非null的引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也必须返回true。
一致性:对于任何非null的引用值x和y,只要equals的比较操作在对象中所用的信息没有被修改,多次调用x.equals(y)就会一致的返回true/false。
非空性:对于任何非null的引用值x,x.equals(null)必须返回false。(抛异常也不行)
对称性违反的例子
package com.ez.impl; /** * 违反对称性 */ public class CaseIgnoreString { private final String s; public CaseIgnoreString(String s){ if(s==null) throw new NullPointerException(); this.s=s; } @Override public boolean equals(Object obj) { if(obj instanceof CaseIgnoreString){ return s.equalsIgnoreCase(((CaseIgnoreString)obj).s); }else if(obj instanceof String){ return s.equalsIgnoreCase((String)obj); } return false; } public static void main(String[] args) { CaseIgnoreString cs=new CaseIgnoreString("EZbcw"); String str="ezbcw"; System.out.println(cs.equals(str)); System.out.println(str.equals(cs)); } }
假如你把不区分大小写的字符串对象放到一个集合中,此时list.contains(s)会返回什么结果呢?没人知道,在Sun的当前实现中,它碰巧返回false。
public boolean contains(Object o) { return indexOf(o) >= 0; } 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; }
一旦违反了equals约定,当其他对象面对你的对象时,你完全不知道这些对象的行为会怎么样。
传递性违反的例子
package com.ez.impl; /** * 长方形 */ public class Oblong { private final int width; private final int length; public Oblong(int width,int length){ this.width=width; this.length=length; } @Override public boolean equals(Object obj) { if(!(obj instanceof Oblong)){ return false; } Oblong oblong=(Oblong)obj; return oblong.width==width&&oblong.length==length; } }
/** * 长方体 */ public class Cuboid extends Oblong{ private int height; public Cuboid(int width,int length,int height){ super(width, length); this.height=height; } @Override public boolean equals(Object obj) { if(!(obj instanceof Oblong)){ return false; //不是长方形直接返回false } else if(!(obj instanceof Cuboid)){ return obj.equals(this); //长方形比较长和宽 } return super.equals(obj)&&((Cuboid)obj).height==height; //长方体比较长宽高 } }
在Java平台类库中,有一些类扩展了可实例化的类,并添加了新的值组件。
例如,java.sql.Timestamp对java.util.Date进行了扩展,并增加了nanoseconds域。
Timestamp的equals实现确实违反了对称性,如果Timestamp和Date对象被用于一个集合中,或者以其他方式被混合在一起,则会引起不正确的行为。
Timestamp类有一个免责声明,告诫程序员不要混合使用Date和Timestamp对象。
覆盖equals时总要覆盖hashCode
如果两个对象根据equals(Object)方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果。
如果两个对象根据equals(Object)方法比较是不相等的,那么调用这两个对象中任意一个对象的hashCode方法,则不一定产生不同的整数结果。
例子:通过List的removeAll方法,重写类的equals和hashcode方法,来实现
package com.ez.test.mytests; import java.util.ArrayList; import java.util.List; /** * 逻辑上认为User的id相同,就认为是同一个人,因为一个用户可以取多个名字,但是id是唯一的。 * 重写equals为了list去重-apps.removeAll(apps1),重写equals必须同时重写hashcode。 * 使用Eclipse自动生成的hashCode */ public class User { private int id; private String name; public static void main( String[] args ) { List<User> apps=new ArrayList<User>(); User app=new User(); app.setId(1); app.setName("张山"); User app1=new User(); app1.setId(2); app1.setName("李四"); User app2=new User(); app2.setId(3); app2.setName("王五"); apps.add(app); apps.add(app1); apps.add(app2); List<User> apps1=new ArrayList<User>(); User app3=new User(); app3.setId(1); app3.setName("孙六"); User app4=new User(); app4.setId(2); app4.setName("陈七"); apps1.add(app3); apps1.add(app4); apps.removeAll(apps1); System.out.println("apps size="+apps.size()+", id="+apps.get(0).getId()+", name="+apps.get(0).getName()); } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + id; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof User)) { return false; } User other = (User) obj; if (id != other.id) { return false; } return true; } }
相关推荐
重载equals方法示例重载equals方法示例重载equals方法示例重载equals方法示例重载equals方法示例
equals()和hashcode()这两个方法都是从object类中继承过来的。当String 、Math、还有Integer、Double。。。。等这些封装类在使用equals()方法时,已经覆盖了object类的equals()方法.
今天小编就为大家分享一篇关于关于Object中equals方法和hashCode方法判断的分析,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
本文讲述了什么时候重写equals方法和如何重写equals方法。
equals(Object) 与 == 的区别
equals方法重写作业,Students类,有三个属性id ,name ,grade。还有一个测试类用于测试创建了三个对象前两各对象的数据完全一样,第三个对象的数据不同。使用equals方法比较。并输出结果。
本文档详细介绍了set接口为什么会用到hashCode和equals方法以及这两个方法的一些探讨 set不同的实现类用到的这两个方法也不同
重写toString和equals方法的意义以及方法
Java中equals方法隐藏的陷阱
要求覆盖基类Object中的ToString()方法和Equals()方法,使得直接输出Student对象时输出的是对象的id,name和age信息;并且当两个对象的学号相同时认为它们相等; 然后写一个主方法测试以上定义。
知识点 比较运算符==和equals方法的比较 知识点 比较运算符==和equals方法的比较
Java中的==与equals()实例方法Java中测试两个变量是否相等的方法有两个,一个是用==运算符,另一个就是object类提供的equals()方法。2
通常,equals方法用于比较两个对象的内容是否一样,这时就需要类去覆盖Object的equals()方法,在equal()方法内自定义相等的规则。; public boolean equals(Object anObject) { if (this == anObject) { return true;...
==和equals方法究竟有什么区别? == 操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用==操作符。 ...
2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2....
js equals 比较两个对象是否相等
本文介绍了Java语言不直接支持关联数组,可以使用任何对象作为一个索引的数组,但在根Object类中使用 hashCode()方法明确表示期望广泛使用HashMap。理想情况下基于散列的容器提供有效插入和有效检索;直接在对象模式...
主要介绍了Object类toString()和equals()方法使用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
equals():反映的是对象或变量具体的值,即两个对象里面包含的值--可能是对象的引用,也可能是值类型的值。 hashCode():计算出对象实例的...当然,当对象所对应的类重写了hashCode()方法时,结果就截然不同了。
这里是一个文档,里边讲解了hashCode与equals方法使用,大家要是不明白,可以去看看