您的位置:首页 > 移动开发 > Objective-C

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

2006-06-13 15:18 453 查看
经常会碰到一些==跟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 {
main(String[] args) {
Integer n1 =  Integer(47);
Integer n2 =  Integer(47);
System.out.println(n1 == n2);
System.out.println(n1 != n2);
}
}


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

EqualsMethod {
main(String[] args) {
Integer n1 =  Integer(47);
Integer n2 =  Integer(47);
System.out.println(n1.equals(n2));
}
}


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

Value {
i;
}

EqualsMethod2 {
main(String[] args) {
Value v1 =  Value();
Value v2 =  Value();
v1.i = v2.i = 100;
System.out.println(v1.equals(v2));
}
}


此时的结果又变回了false!这是由于equals()的默认行为是比较句柄。所以除非在自己的新类中改变了equals(),否则不可能表现出我们希望的行为。不幸的是,要到第7章才会学习如何改变行为。但要注意equals()的这种行为方式同时或许能够避免一些“灾难”性的事件。
大多数Java类库都实现了equals(),所以它实际比较的是对象的内容,而非它们的句柄。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息