`
xichao1929
  • 浏览: 38838 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论
阅读更多

 有Java基础的人都会搞懂一个问题就是equals==的区别是什么.我的文章便从这开始谈起。首先我要告诉你equals==是完全一样的。你可能非常不赞同。请看下面的代码  

 public boolean equals(Object obj) {
	return (this == obj);
    }

 

显然这段代码印证了我刚才的话。那么这段代码从何而来呢,它是object类的一个方法,也就是equals的原形。至于我们所用到的equals==不一样。很简单equals被重写了。我们用到的equals方法不是Object的,而是他的子类的。当然有一个很重要的问题被我忽视了,也就是==比较的是jvm的堆中对象的位置,简单的说就是对象的地址,而不是对象的内容。

重写equals方法的类不止一个我们看看下面的这几个。

<!--EndFragment-->

 

下面看一下和==有点关系的两个代码:

      Integer i1 = 200;
  Integer i2 = 200;
  System.out.println("i1==i2: "+(i1==i2));
和
    Integer i3 = 100;
  Integer i4 = 100;
  System.out.println("i3==i4: "+(i3==i4));
  

这两代码很简单,说一句废话,如果你懂,就会感觉答案很简单,不懂,就傻眼了,哈哈。

<!--EndFragment--> 这两段代码的结果是:

 

      i1==i2: false
  i3==i4: true

 "==" 比较的是两个对象的引用(内存地址)是否相同,也用来比较两个基本数据类型的变量值是否相等。
  在自动装箱时对于值从-128到127之间的值,它们被装箱为Integer对象后,会存在内存中被重用,
  所以范例中,i3 与 i4实际上参考至同一个对象。
  如果超过了从-128到127之间的值,被装箱后的Integer对象并不会被重用,
  即相当于每次装箱时都新建一个 Integer对象,所以范例中,i1与i2参考的是不同的对象。
  另外,当不使用自动装箱功能的时候,情况与普通类对象一样,请看下例:

 

       Integer i3 = new Integer(100);
   Integer i4 = new Integer(100);
   System.out.println("i3==i4: "+(i3==i4));//显示false

 

<!--EndFragment--><!--EndFragment-->
 public boolean equals(Object obj) {
	if (obj instanceof Integer) {
	    return value == ((Integer)obj).intValue();
	}
	return false;
    }

 

这个方法是Integer中的方法,显然这个比较的是对象的内容,即某一Integer对象的值。而不是对象地址了。自然这个时候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;
    }

 

这个是String中的equals方法。因此可以这样解释一下,所要判断的String对象,如果是同

一个对象,则返回true,如果不一样,但是内容一样,也会返回true

关于equals方法的重写有几条规则:

  1)自反性:对于任何非空的引用x'x.equals(x) 应该返回true

  (这也是String中重写equals时,第一个判断的原因)

  2) 对称性:对于任何引用xy,如果x.equals(y)返回true,反过来亦成立。

  3) 传递性:对于任何引用xyz,如果x.equals(y)返回

truey.equals(z)返回true,那么x.equals(z)也应该返回true

  4) 一致性:如果xy引用的对象没有发生变化,那么反复调用

x.equals(y)应该返回同样的结果。

  5) 对于任意非空引用xx.equals(null)应该返回false

下面是对重写equals方法的一些建议:

下面给出编写一个完美的equals方法的建议:

1) 显式参数命名为otherObject,稍后需要将它转换成另一个叫

做 other的变量。

2) 检测thisotherObject是否引用同一个对象:

        if (this == otherObject) return true;

        这条语句只是一个优化。实际上,这是一种经常采用的形

        式。因为计算这个等式要比一个一个地比较类中的域所付

        出的代价小得多。

3) 检测otherObject是否为null,如果为null,返回false。这项

       检测是很必要的。

                if (otherObject == null) return false;

       比较thisotherObject是否属于同一个类。如果equals的语

       义在每个子类中有所改变,就使用getClass检测:

               if (getClass() != otherObject.getClass()) return false;

       如果所有的子类都拥有统一的语义,就使用instanceof检测:

              if (! (otherObject instanceof ClassName)) retrun false;

4)将otherObject转换为相应的类类型变量:

        ClassName other = (ClassName)otherObject;

5) 现在开始对所有需要比较的域进行比较了。使用 == 比较

       基本类型域,使用equals比较对象域。如果所有的域都匹

       配,就返回ture;否则返回false

               return field1 == other.field1

                         && field2.equals(other.field2)

                         && ……;

<!--EndFragment-->

<!--EndFragment-->
1
1
分享到:
评论
4 楼 zhangcan6176 2012-12-12  
LZ牛X
3 楼 dingran 2012-12-12  
我看过Effective Java的关于equal的内容,他里面也提到了这些规则,看来如果要提供这个功能,还是挺复杂的,这是考验一个程序员的时刻啊,呵呵
2 楼 dingran 2012-12-12  
工作几年后,更应该回到这些基本知识上来重新思考,这样的收获能记住一辈子,不会遗忘的知识链。赞许楼主的研究态度!
1 楼 xiaokang1582830 2012-12-12  
这些才是最基础的东西!基础不扎实是无法写出优雅高效的代码

相关推荐

Global site tag (gtag.js) - Google Analytics