- 浏览: 270765 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
muyufenghua:
public static <T super B> ...
浅谈Java泛型中的extends和super关键字 -
wantodare:
class Test1 {
{
a=1;
}
pr ...
Java对象初始化详解 -
wubo2qml:
问下如何进行列中数字大小的比较。我看了几个过滤器,最接近的是S ...
利用Filter进行HBase查询 -
blackproof:
rowkey是A_B我知道要的A集合,也知道要的B范围不用自定 ...
利用Filter进行HBase查询 -
bin_1715575332:
文章不错,尤其了后半部分讲解一些原理。
利用Filter进行HBase查询
equals方法的重要性毋须多言,只要你想比较两个对象是不是同一对象,你就应该实现equals方法,让对象用你认为相等的条件来进行比较.
下面的内容只是API的规范,没有什么太高深的意义,但我之所以最先把它列在这儿,是因为这些规范在事实中并不是真正能保证得到实现.
以上几条规则并不是最完整的表述,详细的请参见API文档.对于Object类,它提供了一个最最严密的实现,那就是只有是同一对象时,equals方法才 返回true,也就是人们常说的引用比较而不是值比较.这个实现严密得已经没有什么实际的意义, 所以在具体子类(相对于Object来说)中,如果我们要进行对象的值比较,就必须实现自己的equals方法.先来看一下以下这段程序:
这是JDK中java.text.FieldPosition的标准实现,似乎没有什么可说的. 我信相大多数或绝大多数程序员认为,这是正确的合法的equals实现.毕竟它是JDK的API实现啊. 还是让我们以事实来说话吧:
运行一下看看会打印出什么: System.out.println(fp.equals(fp1));打印true System.out.println(fp1.equals(fp));打印flase 两个对象,出现了不对称的equals算法.问题出在哪里(脑筋急转弯:当然出在JDK实现的BUG)?
我相信有太多的程序员(除了那些根本不知道实现 equals方法的程序员外)在实现equals方法时都用过instanceof运行符来进行短路优化的,实事求是地说很长一段时间我也这么用过。 太多的教程,文档都给了我们这样的误导。而有些稍有了解的程序员可能知道这样的优化可能有些不对但找不出问题的关键。另外一种极端是知道这个技术缺陷的骨灰级专家就提议不要这样应用。我们知道,"通常"要对两个对象进行比较,那么它们"应该"是同一类型。所以首先利用instanceof运算符进行短路优化,如果被比较的对象不和当前对象是同一类型则不用比较返回false。
但事实上,"子类是父类的一个实例",所以如果子类 o instanceof 父类,始终返回true,这时肯定不会发生短路优化,下面的比较有可能出现多种情况,一种是不能造型成父类而抛出异常,另一种是父类的private成员没有被子类继承而不能进行比较,还有就是形成上面这种不对称比较。可能会出现太多的情况。 那么,是不是就不能用 instanceof运算符来进行优化?答案是否定的,JDK中仍然有很多实现是正确的,如果一个class是final的,明知它不可能有子类,为什么不用 instanceof来优化呢?为了维护SUN的开发小组的声誉,我不说明哪个类中,但有一个小组成员在用这个方法优化时在后加加上了加上了这样的注释:
可能是有些疑问,但不知道如何做(不知道为什么没有打电话给我......)那么对于非final类,如何进行类型的quick check呢?
用被比较对象的class对象和当前对象的class比较,看起来是没有问题.但是,如果这个类的子类没有重新实现equals方法,那么子类在比较的时候,obj.getClass() 肯定不等于XXXCalss.class, 也就是子类的equals将无效,所以
才是正确的比较。另外一个quick check是if(this==obj) return true; 是否equals方法比较的两个对象一定是要同一类型?上面我用了"通常",这也是绝大多数程序员的愿望,但是有些特殊的情况,我们可以进行不同类型的比较,这并不违反规范。但这种特殊情况是非常罕见的,一个不恰当的例子是,Integer类的equals可以和Sort做比较,比较它们的value是不是同一数学值。(事实上JDK的API中并没有这样做,所以我才说是不恰当的例子)在完成quick check以后,我们就要真正实现你认为的“相等”。对于如何实现对象相等,没有太高的要求,比如你自己实现的“人”类,你可以认为只要name相同即认 为它们是相等的,其它的sex, ago都可以不考虑。这是不完全实现,但是如果是完全实现,即要求所有的属性都是相同的,那么如何实现equals方法?
这是一个完全实现,但是,有时equals实现是在父类中实现,而要求被子类继承后equals能正确的工作,这时你并不事实知道子类到底扩展了哪些属性,所以用上面的方法无法使equals得到完全实现。一个好的方法是利用反射来对equals进行完全实现:
为了说明的方便,上明的实现省略了异常,这样的实现放在父类中,可以保证你的子类的equals可以按你的愿望正确地工作。关于equals方法的最后一点是:如果你要是自己重写(正确说应该是履盖)equals方法,那同时就一定要重写hashCode().这是规范,否则.............
我们还是看一下这个例子:
注意这个类是final的,所以这个equals实现没有什么问题。我们来测试一下:
既然pn.equals(pn1),那么我put(pn,"I love you")后,get(pn1)为什么是null呢? 答案是因为它们的hashCode不一样,而hashMap就是以hashCode为主键的。所以规范要求,如果两个对象进行equals比较时如果返回true,那么它们的hashcode要求返回相等的值。
下面的内容只是API的规范,没有什么太高深的意义,但我之所以最先把它列在这儿,是因为这些规范在事实中并不是真正能保证得到实现.
- 对于任何引用类型, o.equals(o) == true成立.
- 如果 o.equals(o1) == true 成立,那么o1.equals(o)==true也一定要成立.
- 如果 o.equals(o1) == true 成立且 o.equals(o2) == true 成立,那么 o1.equals(o2) == true 也成立.
- 如果第一次调用o.equals(o1) == true成立,在o和o1没有改变的情况下以后的任何次调用都成立.
- o.equals(null) == true 任何时间都不成立.
以上几条规则并不是最完整的表述,详细的请参见API文档.对于Object类,它提供了一个最最严密的实现,那就是只有是同一对象时,equals方法才 返回true,也就是人们常说的引用比较而不是值比较.这个实现严密得已经没有什么实际的意义, 所以在具体子类(相对于Object来说)中,如果我们要进行对象的值比较,就必须实现自己的equals方法.先来看一下以下这段程序:
public boolean equals(Object obj) { if (obj == null) return false; if (!(obj instanceof FieldPosition)) return false; FieldPosition other = (FieldPosition) obj; if (attribute == null) { if (other.attribute != null) { return false; } } else if (!attribute.equals(other.attribute)) { return false; } return (beginIndex == other.beginIndex && endIndex == other.endIndex && field == other.field); } }
这是JDK中java.text.FieldPosition的标准实现,似乎没有什么可说的. 我信相大多数或绝大多数程序员认为,这是正确的合法的equals实现.毕竟它是JDK的API实现啊. 还是让我们以事实来说话吧:
package debug; import java.text.*; public class Test { public static void main(String[] args) { FieldPosition fp = new FieldPosition(10); FieldPosition fp1 = new MyTest(10); System.out.println(fp.equals(fp1)); System.out.println(fp1.equals(fp)); } } class MyTest extends FieldPosition { int x = 10; public MyTest(int x){ super(x); this.x = x; } public boolean equals(Object o){ if(o==null) return false; if(!(o instanceof MyTest )) return false; return ((MyTest)o).x == this.x; } }
运行一下看看会打印出什么: System.out.println(fp.equals(fp1));打印true System.out.println(fp1.equals(fp));打印flase 两个对象,出现了不对称的equals算法.问题出在哪里(脑筋急转弯:当然出在JDK实现的BUG)?
我相信有太多的程序员(除了那些根本不知道实现 equals方法的程序员外)在实现equals方法时都用过instanceof运行符来进行短路优化的,实事求是地说很长一段时间我也这么用过。 太多的教程,文档都给了我们这样的误导。而有些稍有了解的程序员可能知道这样的优化可能有些不对但找不出问题的关键。另外一种极端是知道这个技术缺陷的骨灰级专家就提议不要这样应用。我们知道,"通常"要对两个对象进行比较,那么它们"应该"是同一类型。所以首先利用instanceof运算符进行短路优化,如果被比较的对象不和当前对象是同一类型则不用比较返回false。
但事实上,"子类是父类的一个实例",所以如果子类 o instanceof 父类,始终返回true,这时肯定不会发生短路优化,下面的比较有可能出现多种情况,一种是不能造型成父类而抛出异常,另一种是父类的private成员没有被子类继承而不能进行比较,还有就是形成上面这种不对称比较。可能会出现太多的情况。 那么,是不是就不能用 instanceof运算符来进行优化?答案是否定的,JDK中仍然有很多实现是正确的,如果一个class是final的,明知它不可能有子类,为什么不用 instanceof来优化呢?为了维护SUN的开发小组的声誉,我不说明哪个类中,但有一个小组成员在用这个方法优化时在后加加上了加上了这样的注释:
if (this == obj) // quick check return true; if (!(obj instanceof XXXXClass)) // (1) same object? return false;
可能是有些疑问,但不知道如何做(不知道为什么没有打电话给我......)那么对于非final类,如何进行类型的quick check呢?
if(obj.getClass() != XXXClass.class) return false;
用被比较对象的class对象和当前对象的class比较,看起来是没有问题.但是,如果这个类的子类没有重新实现equals方法,那么子类在比较的时候,obj.getClass() 肯定不等于XXXCalss.class, 也就是子类的equals将无效,所以
if(obj.getClass() != this.getClass()) return false;
才是正确的比较。另外一个quick check是if(this==obj) return true; 是否equals方法比较的两个对象一定是要同一类型?上面我用了"通常",这也是绝大多数程序员的愿望,但是有些特殊的情况,我们可以进行不同类型的比较,这并不违反规范。但这种特殊情况是非常罕见的,一个不恰当的例子是,Integer类的equals可以和Sort做比较,比较它们的value是不是同一数学值。(事实上JDK的API中并没有这样做,所以我才说是不恰当的例子)在完成quick check以后,我们就要真正实现你认为的“相等”。对于如何实现对象相等,没有太高的要求,比如你自己实现的“人”类,你可以认为只要name相同即认 为它们是相等的,其它的sex, ago都可以不考虑。这是不完全实现,但是如果是完全实现,即要求所有的属性都是相同的,那么如何实现equals方法?
class Human{ private String name; private int ago; private String sex; public boolean equals(Object obj){ //quick check.... Human other = (Human)ojb; return this.name.equals(other.name) && this.ago == ohter.ago && this.sex.equals(other.sex); } }
这是一个完全实现,但是,有时equals实现是在父类中实现,而要求被子类继承后equals能正确的工作,这时你并不事实知道子类到底扩展了哪些属性,所以用上面的方法无法使equals得到完全实现。一个好的方法是利用反射来对equals进行完全实现:
public boolean equals(Object obj){ //quick check....... Class c = this.getClass(); Filed[] fds = c.getDeclaredFields(); for(Filed f:fds){ if(!f.get(this).equals(f.get(obj))) return false; } return true; }
为了说明的方便,上明的实现省略了异常,这样的实现放在父类中,可以保证你的子类的equals可以按你的愿望正确地工作。关于equals方法的最后一点是:如果你要是自己重写(正确说应该是履盖)equals方法,那同时就一定要重写hashCode().这是规范,否则.............
我们还是看一下这个例子:
public final class PhoneNumber{ private final int areaCode; private final int exchange; private final int extension; public PhoneNumber(int areaCode, int exchange, int extension){ rangeCheck(areaCode, 999, "area code"); rangeCheck(exchange, 99999999, "exchange"); rangeCheck(extension, 9999, "extension"); this.areaCode = areaCode; this.exchange = exchange; this.extension = extension; } private static void rangeCheck(int arg, int max, String name){ if(arg < 0 || arg > max) throw new IllegalArgumentException(name + ": " + arg); } public boolean equals(Object o){ if(o == this) return true; if(!(o instanceof PhoneNumber)) return false; PhoneNumber pn = (PhoneNumber)o; return pn.extension == extension && pn.exchange == exchange && pn.areaCode == areaCode; } }
注意这个类是final的,所以这个equals实现没有什么问题。我们来测试一下:
public static void main(String[] args){ Map hm = new HashMap(); PhoneNumber pn = new PhoneNumber(123, 38942, 230); hm.put(pn, "I love you"); PhoneNumber pn1 = new PhoneNumber(123, 38942, 230); System.out.println(pn); System.out.println("pn.equals(pn1) is " + pn.equals(pn1)); System.out.println(hm.get(pn1)); System.out.println(hm.get(pn)); }
既然pn.equals(pn1),那么我put(pn,"I love you")后,get(pn1)为什么是null呢? 答案是因为它们的hashCode不一样,而hashMap就是以hashCode为主键的。所以规范要求,如果两个对象进行equals比较时如果返回true,那么它们的hashcode要求返回相等的值。
发表评论
-
Java对象初始化详解
2012-07-18 00:43 26934在Java中,一个对象在可 ... -
利用Filter进行HBase查询
2012-07-11 00:14 19784在HBase中,我们可以利 ... -
Java中Enum类型的序列化
2012-07-07 21:53 30654在Java中,对Enum类型的序列化与其他对象类型的序列化有所 ... -
Java final关键字详解
2012-07-07 16:27 3995在java中,final关键字可以有如下的用处: final ... -
利用线程隔离简化并发控制
2012-06-28 01:18 2236在Java中,为了限制多个不同线程对共享变量或者状态的访问,利 ... -
Java内存模型能给我们什么
2012-06-24 15:07 1521首先,为什么需要有内 ... -
java方法调用过程解析和执行--编译器的处理
2012-06-02 15:24 2968本文尝试对java在编译器和运行期如何处理程序代码中的方法调用 ... -
maven杂记
2012-03-02 00:32 2023单独部署一个文件到repo 有时候我们会需要单独部署一个文件到 ... -
浅谈Java泛型中的extends和super关键字
2010-12-25 21:06 18934泛型是在Java 1.5中被加入了,这里不讨论泛型的细节 ... -
Java xml处理概述
2010-12-14 18:21 1564在Java中,对xml的处理模型主要有两种,一种DOM,一种是 ... -
Sun的apt工具及Mirrors包学习
2010-01-05 00:02 4124最近看来一些有关Java Annotation的东西,主要 ... -
Inversion of Control Containers and the Dependency Injection pattern
2009-12-02 23:02 1006One of the entertaining things ... -
Java中Soft,Weak,Phantom应用的区别和使用
2009-10-29 13:20 2376Java 1.2版本之后加入 ... -
java 反射实例化内部类
2009-08-25 13:51 5889内部类的初始化同一般类的初始化基本相同,只是内部类的类名全 ... -
java 泛型-erasure
2009-07-30 12:42 2593Java的泛型实现采用了擦除(erasure)机制,这给获 ... -
正则表达式计算单词出现次数
2009-06-23 16:06 5519给定一段文本,使用正则表达式计算该文本中不同单词的出现次数。 ... -
JDK 1.5 Proxy 动态代理机制分析
2009-06-16 11:34 2532Java的动态代理机制早在其1.3版本就已经引入了。在jdk1 ... -
使Maven 2在package、install等阶段跳过运行Test的配置
2009-06-07 11:52 10522Skipping Tests To skip running ...
相关推荐
Java语言深入_equals
2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2....
Java equals 方法与hashcode 方法的深入解析.rar
本文介绍了Java语言不直接支持关联数组,可以使用任何对象作为一个索引的数组,但在根Object类中使用 hashCode()方法明确表示期望广泛使用HashMap。理想情况下基于散列的容器提供有效插入和有效检索;直接在对象模式...
Java中的==与equals()实例方法Java中测试两个变量是否相等的方法有两个,一个是用==运算符,另一个就是object类提供的equals()方法。2
Java中equals方法隐藏的陷阱
重载equals方法示例重载equals方法示例重载equals方法示例重载equals方法示例重载equals方法示例
java_equals用法,用来熟悉重写equals方法的
7.11 小结:多方位理解Java方法 191 7.12 习题 192 第8章 Java中的包(Package)命名习惯和注释 193 教学视频:43分钟 8.1 Java中的包(Package) 193 8.1.1 Java中的包 193 8.1.2 在Eclipse中使用包 194 ...
能够加强对java中equals与==区别的理解。
本文讲述了什么时候重写equals方法和如何重写equals方法。
java中equals和==的区别.doc java中equals和==的区别.doc
Java重写equals同时需要重写hashCode的代码说明,以及如何重写hashCode方法,此代码演示按照effective java书籍说明的重写思路。代码中演示了使用集合存储对象,并且对象作为key,需重写equals和hashCode.
在java语言当中,equals和==之间究竟有什么区别? 而这道题的答案也是千篇一律: equals是用来比较对象的内容,而==是用来比较java对象的地址。 貌似这个问题大家都已经十分的了解了?为什么我还要单独拿出来说呢?...
答:Java是一种面向对象的编程语言,由Sun Microsystems公司(现属Oracle公司)于1995年推出。它具有简单、对象 oriented、分布式、多线程、动态、 Architecture neutral、高度可移植、安全等特点。 2. 什么是JVM? 答...
详细介绍和讲解Java中的==和equals区别
java 资料 equals 与== 的区别
Object类是所有Java类的根类,它定义了一些常用的方法,例如equals()、hashCode()、toString()等。本案例代码将详细展示Object类的使用方法,并提供一些实际场景下的案例,以帮助开发者更好地理解和运用这些方法。 ...
浅谈Java中的equals和==Java开发Java经验技巧共6页.pdf.zip