- 浏览: 116007 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
playboy0305:
正解。
geeksun 写道在执行操作前,session.cl ...
a different object with the same identifier value -
geeksun:
在执行操作前,session.clear()就行了。
a different object with the same identifier value -
qianqingfu:
文笔太烂!!!!!
a different object with the same identifier value -
oscarswing:
也就是说我写不写都行,反正仅在debug的时候有效,是吧?
ASSERT的用法 -
boreas_baosj:
恩 ~~~
a different object with the same identifier value
什么时候需要重写equals()?
我们知道每一个java类都继承自Object类,equals()是Object类中提供的方法之一。那么,让我们先来看看Object#equals()在Java中的原代码:
public boolean equals(Object obj)
{
return (this == obj);
}
可以看出,只有当一个实例等于它本身的时候,equals()才会返回true值。通俗地说,此时比较的是两个引用是否指向内存中的同一个对象,也可以称做是否实例相等。而我们在使用equals()来比较两个指向值对象的引用的时候,往往希望知道它们逻辑上是否相等,而不是它们是否指向同一个对象。在这样的情况下, 如果超类也没有重写equals()以实现期望的行为,这时我们就需要重写equals方法。而且这样做也使得这个类的实例可以被用做映射表(map)的键,或者集合(set)的元素,并使映射表或者集合表现出预期的行为。
Object类提供的equals方法只是一个很简单的,不能适应应用程序有特殊要求的情况。
比如网络对象,带有volatile属性的对象,或是带有多层子对象的复合对象,等等,是不能像String一类的对象进行简单比较的,所以提供了这样一个机制,就像serializable接口一样,既有默认的序列化方法,也提供了程序自己定制,覆盖默认方式的可能性。
Object仅仅提供了一个对引用的比较,如果两个引用不是同一个那就返回false,这是无法满足大多数对象比较的需要的,所以要覆盖。
怎样重写equals()方法?
重写equals()方法看起来非常简单,但是有许多改写的方式会导致错误,并且后果非常严重。要想正确改写equals()方法,你必须要遵守它的通用约定。下面是约定的内容,来自java.lang.Object的规范:
equals方法实现了等价关系(equivalence relation):
1. 自反性:对于任意的引用值x,x.equals(x)一定为true。
2. 对称性:对于任意的引用值x 和 y,当x.equals(y)返回true时,
y.equals(x)也一定返回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. 非空性:对于任意的非空引用值x,x.equals(null)一定返回false。
接下来我们通过实例来理解上面的约定。我们首先以一个简单的非可变的二维点类作为开始:
public class Point{
private final int x;
private final int y;
public Point(int x, int y){
this.x = x;
this.y = y;
}
public boolean equals(Object o){
if(!(o instanceof Point))
return false;
Point p = (Point)o;
return p.x == x && p.y == y;
}
}
假设你想要扩展这个类,为一个点增加颜色信息:
public class ColorPoint extends Point{
private Color color;
public ColorPoint(int x, int y, Color color){
super(x, y);
this.color = color;
}
//override equasl()
public boolean equals(Object o){
if(!(o instanceof ColorPoint))
return false;
ColorPoint cp = (ColorPoint)o;
return super.equals(o) && cp.color==color;
}
}
我们重写了equals方法,只有当实参是另一个有色点,并且具有同样的位置和颜色的时候,它才返回true。可这个方法的问题在于,你在比较一个普通点和一个有色点,以及反过来的情形的时候,可能会得到不同的结果:
public static void main(String[] args){
Point p = new Point(1, 2);
ColorPoint cp = new ColorPoint(1, 2, Color.RED);
System.out.println(p.equals(cp));
System.out.println(cp.eqauls(p));
}
运行结果:
true
false
这样的结果显然违反了对称性,你可以做这样的尝试来修正这个问题:让ColorPoint.equals在进行“混合比较”的时候忽略颜色信息:
public boolean equals(Object o){
if(!(o instanceof Point))
return false;
//如果o是一个普通点,就忽略颜色信息
if(!(o instanceof ColorPoint))
return o.equals(this);
//如果o是一个有色点,就做完整的比较
ColorPoint cp = (ColorPoint)o;
return super.equals(o) && cp.color==color;
}
这种方法的结果会怎样呢?让我们先来测试一下:
public static void main(String[] args){
ColorPoint p1 = new ColorPoint(1, 2, Color.RED);
Point p2 = new Point(1, 2);
ColorPoint p3 = new ColorPoint(1, 2, Color.BLUE);
System.out.println(p1.equals(p2));
System.out.println(p2.equals(p1));
System.out.println(p2.equals(p3));
System.out.println(p1.eqauls(p3));
}
运行结果:
true
true
true
false
这种方法确实提供了对称性,但是却牺牲了传递性(按照约定,p1.equals(p2)和p2.eqauals(p3)都返回true,p1.equals(p3)也应返回true)。要怎么解决呢?事实上,这是面向对象语言中关于等价关系的一个基本问题。要想在扩展一个可实例化的类的同时,既要增加新的特征,同时还要保留equals约定,没有一个简单的办法可以做到这一点。新的解决办法就是不再让ColorPoint扩展Point,而是在ColorPoint中加入一个私有的Point域,以及一个公有的视图(view)方法:
public class ColorPoint{
private Point point;
private Color color;
public ColorPoint(int x, int y, Color color){
point = new Point(x, y);
this.color = color;
}
//返回一个与该有色点在同一位置上的普通Point对象
public Point asPoint(){
return point;
}
public boolean equals(Object o){
if(o == this)
return true;
if(!(o instanceof ColorPoint))
return false;
ColorPoint cp = (ColorPoint)o;
return cp.point.equals(point)&&
cp.color.equals(color);
}
}
还有另外一个解决的办法就是把Point设计成一个抽象的类(abstract class),这样你就可以在该抽象类的子类中增加新的特征,而不会违反equals约定。因为抽象类无法创建类的实例,那么前面所述的种种问题都不会发生。
重写equals方法的要点:
1. 使用==操作符检查“实参是否为指向对象的一个引用”。
2. 使用instanceof操作符检查“实参是否为正确的类型”。
3. 把实参转换到正确的类型。
4. 对于该类中每一个“关键”域,检查实参中的域与当前对象中对应的域值是否匹
配。对于既不是float也不是double类型的基本类型的域,可以使用==操作符
进行比较;对于对象引用类型的域,可以递归地调用所引用的对象的equals方法;
对于float类型的域,先使用Float.floatToIntBits转换成int类型的值,
然后使用==操作符比较int类型的值;对于double类型的域,先使用
Double.doubleToLongBits转换成long类型的值,然后使用==操作符比较
long类型的值。
5. 当你编写完成了equals方法之后,应该问自己三个问题:它是否是对称的、传
递的、一致的?(其他两个特性通常会自行满足)如果答案是否定的,那么请找到
这些特性未能满足的原因,再修改equals方法的代码。
我们知道每一个java类都继承自Object类,equals()是Object类中提供的方法之一。那么,让我们先来看看Object#equals()在Java中的原代码:
public boolean equals(Object obj)
{
return (this == obj);
}
可以看出,只有当一个实例等于它本身的时候,equals()才会返回true值。通俗地说,此时比较的是两个引用是否指向内存中的同一个对象,也可以称做是否实例相等。而我们在使用equals()来比较两个指向值对象的引用的时候,往往希望知道它们逻辑上是否相等,而不是它们是否指向同一个对象。在这样的情况下, 如果超类也没有重写equals()以实现期望的行为,这时我们就需要重写equals方法。而且这样做也使得这个类的实例可以被用做映射表(map)的键,或者集合(set)的元素,并使映射表或者集合表现出预期的行为。
Object类提供的equals方法只是一个很简单的,不能适应应用程序有特殊要求的情况。
比如网络对象,带有volatile属性的对象,或是带有多层子对象的复合对象,等等,是不能像String一类的对象进行简单比较的,所以提供了这样一个机制,就像serializable接口一样,既有默认的序列化方法,也提供了程序自己定制,覆盖默认方式的可能性。
Object仅仅提供了一个对引用的比较,如果两个引用不是同一个那就返回false,这是无法满足大多数对象比较的需要的,所以要覆盖。
怎样重写equals()方法?
重写equals()方法看起来非常简单,但是有许多改写的方式会导致错误,并且后果非常严重。要想正确改写equals()方法,你必须要遵守它的通用约定。下面是约定的内容,来自java.lang.Object的规范:
equals方法实现了等价关系(equivalence relation):
1. 自反性:对于任意的引用值x,x.equals(x)一定为true。
2. 对称性:对于任意的引用值x 和 y,当x.equals(y)返回true时,
y.equals(x)也一定返回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. 非空性:对于任意的非空引用值x,x.equals(null)一定返回false。
接下来我们通过实例来理解上面的约定。我们首先以一个简单的非可变的二维点类作为开始:
public class Point{
private final int x;
private final int y;
public Point(int x, int y){
this.x = x;
this.y = y;
}
public boolean equals(Object o){
if(!(o instanceof Point))
return false;
Point p = (Point)o;
return p.x == x && p.y == y;
}
}
假设你想要扩展这个类,为一个点增加颜色信息:
public class ColorPoint extends Point{
private Color color;
public ColorPoint(int x, int y, Color color){
super(x, y);
this.color = color;
}
//override equasl()
public boolean equals(Object o){
if(!(o instanceof ColorPoint))
return false;
ColorPoint cp = (ColorPoint)o;
return super.equals(o) && cp.color==color;
}
}
我们重写了equals方法,只有当实参是另一个有色点,并且具有同样的位置和颜色的时候,它才返回true。可这个方法的问题在于,你在比较一个普通点和一个有色点,以及反过来的情形的时候,可能会得到不同的结果:
public static void main(String[] args){
Point p = new Point(1, 2);
ColorPoint cp = new ColorPoint(1, 2, Color.RED);
System.out.println(p.equals(cp));
System.out.println(cp.eqauls(p));
}
运行结果:
true
false
这样的结果显然违反了对称性,你可以做这样的尝试来修正这个问题:让ColorPoint.equals在进行“混合比较”的时候忽略颜色信息:
public boolean equals(Object o){
if(!(o instanceof Point))
return false;
//如果o是一个普通点,就忽略颜色信息
if(!(o instanceof ColorPoint))
return o.equals(this);
//如果o是一个有色点,就做完整的比较
ColorPoint cp = (ColorPoint)o;
return super.equals(o) && cp.color==color;
}
这种方法的结果会怎样呢?让我们先来测试一下:
public static void main(String[] args){
ColorPoint p1 = new ColorPoint(1, 2, Color.RED);
Point p2 = new Point(1, 2);
ColorPoint p3 = new ColorPoint(1, 2, Color.BLUE);
System.out.println(p1.equals(p2));
System.out.println(p2.equals(p1));
System.out.println(p2.equals(p3));
System.out.println(p1.eqauls(p3));
}
运行结果:
true
true
true
false
这种方法确实提供了对称性,但是却牺牲了传递性(按照约定,p1.equals(p2)和p2.eqauals(p3)都返回true,p1.equals(p3)也应返回true)。要怎么解决呢?事实上,这是面向对象语言中关于等价关系的一个基本问题。要想在扩展一个可实例化的类的同时,既要增加新的特征,同时还要保留equals约定,没有一个简单的办法可以做到这一点。新的解决办法就是不再让ColorPoint扩展Point,而是在ColorPoint中加入一个私有的Point域,以及一个公有的视图(view)方法:
public class ColorPoint{
private Point point;
private Color color;
public ColorPoint(int x, int y, Color color){
point = new Point(x, y);
this.color = color;
}
//返回一个与该有色点在同一位置上的普通Point对象
public Point asPoint(){
return point;
}
public boolean equals(Object o){
if(o == this)
return true;
if(!(o instanceof ColorPoint))
return false;
ColorPoint cp = (ColorPoint)o;
return cp.point.equals(point)&&
cp.color.equals(color);
}
}
还有另外一个解决的办法就是把Point设计成一个抽象的类(abstract class),这样你就可以在该抽象类的子类中增加新的特征,而不会违反equals约定。因为抽象类无法创建类的实例,那么前面所述的种种问题都不会发生。
重写equals方法的要点:
1. 使用==操作符检查“实参是否为指向对象的一个引用”。
2. 使用instanceof操作符检查“实参是否为正确的类型”。
3. 把实参转换到正确的类型。
4. 对于该类中每一个“关键”域,检查实参中的域与当前对象中对应的域值是否匹
配。对于既不是float也不是double类型的基本类型的域,可以使用==操作符
进行比较;对于对象引用类型的域,可以递归地调用所引用的对象的equals方法;
对于float类型的域,先使用Float.floatToIntBits转换成int类型的值,
然后使用==操作符比较int类型的值;对于double类型的域,先使用
Double.doubleToLongBits转换成long类型的值,然后使用==操作符比较
long类型的值。
5. 当你编写完成了equals方法之后,应该问自己三个问题:它是否是对称的、传
递的、一致的?(其他两个特性通常会自行满足)如果答案是否定的,那么请找到
这些特性未能满足的原因,再修改equals方法的代码。
发表评论
-
JAVA最全的编码规范
2008-08-01 14:43 1219(1) 类名首字母应该大写。字段、方法以及对象(句柄)的首字母 ... -
java读写xml操作
2008-07-30 13:14 17414先定义一个简单的input.xml结构,让java进行inpu ... -
Java初学者都必须理解的六大问题
2008-07-29 18:14 1135Java初学者都必须理解的 ... -
HW interview2
2008-07-29 17:33 11661、有哪些数据类型 Java定义了8种简单类型:byte、 ... -
HW interview
2008-07-29 17:32 10021、有哪些数据类型 Java定义了8种简单类型:byte、 ... -
ORA-12516
2008-07-28 13:41 3961ORA-12516, TNS:listener could n ... -
Algorithmic Efficiency02
2008-07-28 10:51 1067The ability to analyze a piece ... -
Algorithmic Efficiency01
2008-07-28 10:50 1114Algorithmic Efficiency -- Beati ... -
Java语言的26个细节03
2008-07-27 10:20 14155,String类和对象池 我们知道得到String对象 ... -
Java语言的26个细节02-浅复制与深复制
2008-07-27 10:16 11214,浅复制与深复制 1)浅复制与深复制概念 ⑴浅复制(浅克隆) ... -
Java语言的26个细节01
2008-07-27 10:15 1360Java作为一门优秀的面向 ... -
Java面试题-答案
2008-07-25 21:20 1002Java面试题(答案) 第 ... -
Java陷阱
2008-07-25 21:14 965面试是没什么道理可讲的,它的题目有的不合情理、脱离实际。有在纸 ... -
ant使用简介
2008-07-25 09:19 952ant使用简介 原地址:http://www ... -
理解“回调函数”
2008-07-25 00:01 1775java理解“回调函数” ... -
使用回调和线程处理一个耗时响应过程
2008-07-24 23:55 1091使用回调和线程处理一个耗时响应过程 现在程序中有许多涉及长耗 ... -
对象的串行化
2008-07-24 21:32 932转载自http://gardenlee.bokee ... -
Java虚拟机类装载:原理、实现与应用
2008-07-24 09:28 1012By jorren 发表于 2005-12-21 15:13: ... -
ASSERT的用法
2008-07-23 14:50 3675ASSERT的用法 ASSERT( booleanExpres ... -
cookie机制和session机制
2008-07-22 09:06 1885一、cookie机制和session机 ...
相关推荐
Java重写equals同时需要重写hashCode的代码说明,以及如何重写hashCode方法,此代码演示按照effective java书籍说明的重写思路。代码中演示了使用集合存储对象,并且对象作为key,需重写equals和hashCode.
equals方法重写作业,Students类,有三个属性id ,name ,grade。还有一个测试类用于测试创建了三个对象前两各对象的数据完全一样,第三个对象的数据不同。使用equals方法比较。并输出结果。
计算机后端-Java-Java核心基础-第14章 面向对象06 14. 重写equals().avi
为什么重写 equals() 时必须重写 hashCode() 方法? String String、StringBuffer、StringBuilder 的区别? String 为什么是不可变的? 字符串拼接用“+” 还是 StringBuilder? String#equals() 和 Object#equals() ...
1、何时需要重写equals() 当一个类有自己特有的“逻辑相等”概念(不同于对象身份的概念)。 2、为什么改写equals()的时候,总是要改写hashCode() 两个原则: hashCode()的返回值和equals()的关系...
equals():反映的是对象或变量具体的值,即两个对象里面包含的值--可能是对象的引用,也可能是值类型的值。 hashCode():计算出对象实例的...当然,当对象所对应的类重写了hashCode()方法时,结果就截然不同了。
在Java和其他一些高级面向对象的编程语言中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖...
hashCode()和equals()定义在Object类中,这个类是所有java类的基类,所以所有的java类都继承这两个方法。 使用hashCode()和equals() hashCode()方法被用来获取给定对象的整数。这个整数被用来确定对象被...
动力节点的Java课程适合绝对零基础的观看,教程中讲解了Java开发环境搭建、Java的基础语法、Java的面向对象。每一个知识点都讲解的非常细腻,由浅入深。适合非计算机专业,想转行做Java开发的朋友,或者想让Java基础...
下面小编就为大家带来一篇浅谈java中BigDecimal的equals与compareTo的区别。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
前言 对于开发的程序员小伙伴,大家肯定对于==和equals不陌生,而且会经常用到他...String对象重写了 equals,比较的是变量值 从上面我们笼统的来说明了一下两者的不同,那么接下来我们看看具体的区分 对象类型的比较
Java面向对象 1 1 学习方法与要求 1 2 面向对象语言与面向过程语言的区别 7 3 面向对象?什么对象? 8 4 什么是类? 9 5 如何创建一个类Class? 10 6 如何使用类创建对象 10 7 引用与实例 11 8 实例属性与实例方法 ...
实验1 String类的常用方法 19 实验2 比较日期的大小 21 实验3 处理大整数 22 上机实践6 组件及事件处理 23 实验1 算术测试 23 实验2 信号灯 25 实验3 布局与日历 28 上机实践7 组件及事件处理2 31 实验1 方程求根 31...
要注意的是List,Set,Queue继承了Collection接口,...这里想用一个简单的例子展示一下他们的使用,内容包括:List、Map、Set、Queue,Collections、Comparable与Comparator,排序、搜索,内部类,泛型、重写equals、hashCode
JDK 和 JRE 有什么区别? JDK(Java Development Kit),Java开发工具包 JRE(Java Runtime Environment),Java运行环境 JDK中包含JRE,JDK中有一个名为jre的...如果重写了equals方法,equals比较的是对象的内容;
如果重写了equals方法,equals比较的是对象的内容; final 在 java 中有什么作用? final修饰的成员变量,必须在声明的同时赋值,一旦创建不可修改; final修饰的方法,不能被子类重写; final类中的方法默认是...
JDK(Java Development Kit),Java开发工具包 JRE(Java Runtime Environment),Java运行环境 JDK中包含JRE,JDK中有一个名为jre的目录,里面包含两个文件夹...如果重写了equals方法,equals比较的是对象的内容;
5.如果重写了equals方法,equals比较的是对象的内容; 3、final 在 java 中有什么作用? (1)用来修饰一个引用 1.如果引用为基本数据类型,则该引用为常量,该值无法修改; 2.如果引用为引用数据类型,比如对象、...
Object类是所有Java类的根类,它定义了一些常用的方法,例如equals()、hashCode()、toString()等。本案例代码将详细展示Object类的使用方法,并提供一些实际场景下的案例,以帮助开发者更好地理解和运用这些方法。 ...
动力节点的Java课程适合绝对零基础的观看,教程中讲解了Java开发环境搭建、Java的基础语法、Java的面向对象。每一个知识点都讲解的非常细腻,由浅入深。适合非计算机专业,想转行做Java开发的朋友,或者想让Java基础...