关于equals()和==操作的一点理解

转载 2006年06月13日 15:18:00

经常会碰到一些==跟equals()方法的误用的例子,有时候自己也说不准就弄混了,特地查了些资料写个小小的总结;
首先大致声明一下默认的情况Object的==操作跟equals()是等效的;有些同志会说我错了,会说==操作是比较是否同
一对象的,equals()是比较两个对象内容是否相等的;这样的说法可以说对了一小半,错了一大半;
首先我们来看下Object对象的equals()方法是怎么实现的:
    public boolean equals(Object obj) {
    return (this == obj);
    }
 如何?这里已经很明显的告诉大家Object的==操作跟equals()是等效的吧.那有朋友就会问那怎么实现让equals()跟==操作不一样呢?
 怎么让equals()方法比较两个对象的内容呢?
 答案就是重写equals()方法;下面需要提到重写equals()方法要注意的几点规范:
 自反reflexive:    x.equals(x)  
 对称symmetric:    x.equals(y)=>y.equals(x)
 传递transitive:    x.equals(y),<code>y.equals(z) =>x.equals(z)
 稳定consistent:    x.equals(y) 每次调用的时候总是确定的返回true or false
 非空        x.equals(null) return false
 从属于==操作    x==y=> x.equals(y) return true

 还有非常重要的一点:改写equals()方法后,必须也要改写hashCode()方法; x.equals(y) => x.hashCode()==y.hashCode();
 上面解释了一堆关于重写equals()方法的原则,现在我们就倒过头来看看一些已经重写了equals()方法的具体的例子;首先拿String类型来考察
 //*************override equals()****************************
 public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = count;
        if (n == anotherString.count) {
        char v1[] = value;
        char v2[] = anotherString.value;
        int i = offset;
        int j = anotherString.offset;
        while (n-- != 0) {
            if (v1[i++] != v2[j++])
            return false;
        }
        return true;
        }
    }
    return false;
    }
//*************override hashCode()****************************
    public int hashCode() {
    int h = hash;
    if (h == 0) {
        int off = offset;
        char val[] = value;
        int len = count;

            for (int i = 0; i < len; i++) {
                h = 31*h + val[off++];
            }
            hash = h;
        }
        return h;
    }
    String类型通过重写了equals(),hashCode()方法实现了String对象的内容比较;基本类型的对象型比如Integer,Long,Float等类型都
    实现了自己的equals()方法;正因为基本类型都实现了对象的内容比较,所以经常给我们一种想当然的equals()是比较对象内容的错误观点.
    如果我们自己写的类要实现内容比较我们就需要自己重写equals()跟hashCode()方法,关于hashCode()的重写建议参考下String的处理方式,
    要尽量避免内容不相等的对象产生相同的hashCode()的错误,否则就会在hashTable中碰到散列值重复的问题,这个按下不表.

    最后额外的讲一下String的==的问题.经常碰到别人问String str="abc";String str2=new String("abc") String str3="abc"中有几个对象的无聊问题.
    这里我给出我自己的解释共str,str2,str3,"abc", new String("abc")五个对象.其中str,str2,str3是reference对象存于JVM的STACK中,"abc"是一个内存对象容纳
    了"abc"这个数据,存在于JVM的String池中(str,str3指向的"abc"是同一内存区--String池中的"abc"),new String("abc")是一个内存对象容纳了"abc"这个数据,存在
    于JVM的Heap 堆中;
    按照上面的解释我们可以明确知道str != str2,因为他们在内存中是两个对象(一个在STRING池中一个在HEAP堆中), str == str3因为他们指向的是String池中的同一对象;
    我们通过str="abc";str3="abc"实例化时,JVM会检查String池中是否已经存在"abc"对象,如果有那么就把引用指向已经存在的"abc";否则就在String池中新建立一个.
    我们通过str2=new String("abc")实例化时,首先这里分配的内存跟STRING池是没有任何关系的,无论HEAP堆和STRING池中有无"abc" JVM都会在HEAP堆里新建立一个
    "abc"对象;

 

 

检查对象是否相等
关系运算符==和!=也适用于所有对象,但它们的含义通常会使初涉Java领域的人找不到北。下面是一个例子:

//: Equivalence.java

public class Equivalence {
  public static void main(String[] args) {
    Integer n1 = new Integer(47);
    Integer n2 = new Integer(47);
    System.out.println(n1 == n2);
    System.out.println(n1 != n2);
  }
} ///:~


其中,表达式System.out.println(n1 == n2)可打印出内部的布尔比较结果。一般人都会认为输出结果肯定先是true,再是false,因为两个Integer对象都是相同的。但尽管对象的内容相同,句柄却是不同的,而==和!=比较的正好就是对象句柄。所以输出结果实际上先是false,再是true。这自然会使第一次接触的人感到惊奇。
若想对比两个对象的实际内容是否相同,又该如何操作呢?此时,必须使用所有对象都适用的特殊方法equals()。但这个方法不适用于“主类型”,那些类型直接使用==和!=即可。下面举例说明如何使用:

//: EqualsMethod.java

public class EqualsMethod {
  public static void main(String[] args) {
    Integer n1 = new Integer(47);
    Integer n2 = new Integer(47);
    System.out.println(n1.equals(n2));
  }
} ///:~


正如我们预计的那样,此时得到的结果是true。但事情并未到此结束!假设您创建了自己的类,就象下面这样:

//: EqualsMethod2.java

class Value {
  int i;
}

public class EqualsMethod2 {
  public static void main(String[] args) {
    Value v1 = new Value();
    Value v2 = new Value();
    v1.i = v2.i = 100;
    System.out.println(v1.equals(v2));
  }
} ///:~


此时的结果又变回了false!这是由于equals()的默认行为是比较句柄。所以除非在自己的新类中改变了equals(),否则不可能表现出我们希望的行为。不幸的是,要到第7章才会学习如何改变行为。但要注意equals()的这种行为方式同时或许能够避免一些“灾难”性的事件。
大多数Java类库都实现了equals(),所以它实际比较的是对象的内容,而非它们的句柄。

相关文章推荐

对equals和==的一点理解

概述:         简单的来说,equals是比较内容,==是比较地址值 详细:        内存可以分为堆内存和栈内存,简单的理解一般栈中主要存放一些基本类型的变量(,int, short, ...

关于ARM 汇编 指令 操作范围的一点理解

在ARM汇编指令中,一些指令对常量的操作做出了一定的限制,         比如 mov指令对常数的操作的规定是 必须是8位二进制循环移位得到的整数。       &...

一点没。操作隐藏工具

  • 2009-06-08 17:02
  • 1.15MB
  • 下载

17-4:ArrayList的contains/remove对对象操作关联equals的详解

package test; import java.util.ArrayList; import java.util.Iterator; class Person { private Stri...

关于PDO操作的一点笔记

关于I/O操作的一点整理

今天遇到一个程序bug,A向B发送完整的一段数据,B却总是不能获取到结尾部分的内容。后来才发现在进行“write”操作(ngx.print)后还需要调用flush操作(ngx.flush)才能将数据写...
  • ciaos
  • ciaos
  • 2012-05-30 22:20
  • 610

每天学一点MATLAB函数——软件操作函数

1. exit 关闭MATLAB函数 2. clc 清空命令窗口 3. commandhistory 打开CommandHistory窗口,若已经打开则选中该窗口 4. diary ...

关于String替换操作的一点笔记

最近项目需要抓取学校百合的一些热点信息,免不了频繁使用正则和String的一些替换操作,遇到了一些问题,值得小记一下。 下面是一个操作的片段 Pattern textareaContent =...

微信支付的一点操作经验

项目经验:一。为了安全起见,demo里很多取值的方法由后台直接提供 (官方的代码里面 是建议genPackage 这个方法在服务端生成。这里只是一个签名在服务端生成。 那么依据之前做支付宝的逻...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)