- 浏览: 215526 次
- 性别:
- 来自: 天津
文章分类
最新评论
-
sun.zhang:
这个文章不错,怎么没人顶?
servlet 输出中文显示为问号"??"的解决办法 -
freeskywcy:
happy90 写道Keep-Alive 模式只要设置一下就行 ...
有关http Keep-Alive 的详细解释 -
happy90:
Keep-Alive 模式只要设置一下就行吗? 那编程的时候要 ...
有关http Keep-Alive 的详细解释
网上关于equals 和 == 的区别的讨论巨多
这里先简单分析下他们的区别吧:
equals 方法(是String类从它的超类Object中继承的)被用来检测两个对象是否相等,即两个对象的内容是否相等。
==用于比较引用和比较基本数据类型时具有不同的功能:
比较基本数据类型,如果两个值相同,则结果为true
而在比较引用时,如果引用指向内存中的同一对象,结果为true
Eg:s1 = new String("sony"); //创建的是字符串对象
s1.equals("sony"); //返回
trues1 == "sony" //返回false
//如果
s1 = "sony";
s1 == "sony" //返回true
OK.开始说Java equals方法
equals方法的重要性毋须多言,只要你想比较两个对象是不是同一对象,你就应该实现equals方法,让对象用你认为相等的条件来进行比较.
下面的内容只是API的规范,没有什么太高深的意义,但我之所以最先把它列在这儿,是因为这些规范在事实中并不是真正能保证得到实现.
1.对于任何引用类型, o.equals(o) == true成立.
2.如果 o.equals(o1) == true 成立,那么o1.equals(o)==true也一定要成立.
3.如果 o.equals(o1) == true 成立且 o.equals(o2) == true 成立,那么
o1.equals(o2) == true 也成立.
4.如果第一次调用o.equals(o1) == true成立,在o和o1没有改变的情况下以后的任何次调用都成立.
5.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要求返回相等的值。
参考文献:http://java.ccidnet.com/art/3737/20071113/1274133_1.html
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/defonds/archive/2009/04/12/4066395.aspx
发表评论
-
Integer.parseInt()和这个Integer.valueOf()的详解
2011-09-20 21:25 1535static int parseInt(String s) ... -
JDBC连接Oracle操作详解
2011-09-18 21:39 1480在进一步学习之前,先学习通过JDBC访问数据库。目的:为了更好 ... -
JSP中<% %>的简单解释
2011-09-18 19:53 1072编译器指示 <%@ 编译器指示 %> 声明 ... -
一个DBManager类(针对各种数据库连接操作的代码)
2011-09-18 19:50 11319package com.function; import ja ... -
一个经典的jsp链接oracle数据库的操作
2011-09-18 19:44 19801.运行环境:jakarta-tomcat-5.0.25 +o ... -
各种常见java_sql_SQLException归纳
2011-09-18 17:46 956java.sql.SQLException错误,将英文原文一并 ... -
Date toLocaleString()、toLocaleDateString()、toLocaleTimeString()方法
2011-09-17 16:45 2523Date ... -
java 中Object的equals函数和对象重写的解释及示例
2011-09-16 21:52 1156Object类里有一个equals方法,以下是针对这个方法的理 ... -
web.xml里<filter-mapping>中的<dispatcher>解释
2011-09-16 21:08 9312.4版本的servlet规范在部属描述符中新增加了一个< ... -
对于@SuppressWarnings 详解
2011-09-16 21:03 759@SuppressWarnings J2SE 提供 ... -
免安装版tomcat如何开机自动启动
2011-09-15 14:54 746说明: 1.新建环境变量: 我的电脑(右击)-属性-高级- ... -
java中基本输入输出流的解释
2011-09-15 12:56 807网络程序的很大一部分 ... -
有关MyEclipse中设置的Content Assist快捷键
2011-09-15 11:11 1530困扰着已久的content assisst问题(代码自动提示快 ... -
使用EditPlus技巧,提高工作效率(自动完成文件、语法文件下载)
2011-09-15 09:51 2140除了windows操作系统,Edi ... -
java API chm html 1.5 1.6 中文版英文版 帮助文档
2011-09-15 09:11 3047J2SE DK & API下载 ————————- h ...
相关推荐
【Java面试题】equals与==的区别
equals(Object) 与 == 的区别
能够加强对java中equals与==区别的理解。
java中equals和==的区别.doc java中equals和==的区别.doc
本文中详细的阐述了Java中经常遇到的equals、hashcode以及“==”号三者之间的区别
2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2....
java中比较值大小,==和equals的区别,基本数据类型和引用数据类型比较值方法
java_equals用法,用来熟悉重写equals方法的
java 资料 equals 与== 的区别
Java中的==与equals()实例方法Java中测试两个变量是否相等的方法有两个,一个是用==运算符,另一个就是object类提供的equals()方法。2
Java equals 方法与hashcode 方法的深入解析.rar
重载equals方法示例重载equals方法示例重载equals方法示例重载equals方法示例重载equals方法示例
equals和==的区别?...大家对于equals这个函数的理解不够深入,只凭上面的一句话,我们是无法了解equals这个函数的来龙去脉的。 第二我个人认为这个问题出的非常的愚蠢,所以忍不住拿出来调侃一下,呵呵。
主要介绍了java 中equals和==的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
浅谈Java中的equals和==Java开发Java经验技巧共6页.pdf.zip
详细介绍和讲解Java中的==和equals区别
Java中equals方法隐藏的陷阱
主要介绍了java 中String.equals和==的比较的相关资料,需要的朋友可以参考下
Java语言深入_equals