黑马程序员-java笔记之equals和hascode方法总结。

1.equals()和==操作符

先谈谈equals()方法和==操作符吧。有一个Book类,如下代码:

[java]  view plain  copy
  1. public class Book {  
  2.       
  3.     private String name;  
  4.     private int price;  
  5.       
  6.     public Book(String name, int price) {  
  7.         super();  
  8.         this.name = name;  
  9.         this.price = price;  
  10.     }     
  11. }  

当用equal和==比较两个Book的实例对象时,均为false:

[java]  view plain  copy
  1. Book book = new Book("java"11);  
  2. Book book1 = new Book("java"11);  
  3. System.out.println(book == book1); //false  
  4. System.out.println(book.equals(book1));//false  

这是内存布局图:


new出book1和book两个Book的实例对象时,内存布局如上图,book和book1两个变量的值均在栈内存中分配,其存储的是两个book对象的内存地址。

使用==比较两个对象:其实是在比较两个对象的引用的值。

book == book1实际上是在比较0X00F1 == 0X00F2是否相等,答案肯定是不等的。用==在比较时,有如下规则:

1.基本数据类型,也称原始数据类型。byte,short,char,int,long,float,double,boolean
他们之间的比较,应用双等号(==),比较的是他们的值。 
2.复合数据类型(类) 
当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。 


使用equals比较两个对象:结果也为false,equals方法继承自Object类,其内容如下:

[java]  view plain  copy
  1. public boolean equals(Object obj) {  
  2. urn (this == obj);  
  3. }  
从这个方法中可以看出,只有当一个实例等于它本身的时候,equals()才会返回true值。通俗地说,此时比较的是两个引用是否指向内存中的同一个对象,也可以称做是否实例相等。而我们在使用equals()来比较两个指向值对象的引用的时候,往往希望知道它们逻辑上是否相等,而不是它们是否指向同一个对象——所以在此我们要重写equals方法,使得两个逻辑上相等的Book对象在比较时相等。

要重写equals方法必须遵守重写规范,如果不遵守,则会导致很多错误,

下面是约定的内容,来自java.lang.Object的规范,equals方法实现了等价关系,以下是要求遵循的5点

1. 自反性:对于任意的引用值x,x.equals(x)一定为true。 

2. 对称性:对于任意的引用值x 和 y,当x.equals(y)返回true时,y.equals(x)也一定返回true。 

3. 传递性:对于任意的引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也一定返回true。

4. 一致性:对于任意的引用值x 和 y,如果用于equals比较的对象信息没有被修改,多次调用x.equals(y)要么一致地返回true,要么一致地返回false。

5. 非空性:对于任意的非空引用值x,x.equals(null)一定返回false。

 重写equals方法后最好重写hashCode方法,否则两个等价对象可能得到不同的hashCode,这在集合框架中使用可能产生严重后果。所以除了要遵守以上五点以外,还要同时重写hascode方法。

2.hashcode方法

 定义:public native int hashCode(); 

说明是一个本地方法,它的实现是根据本地机器相关的。再看它比较“官方”的详细说明:hashCode()返回该对象的哈希码值,该值通常是一个由该对象的内部地址转换而来的整数,它的实现主要是为了提高哈希表(例如java.util.Hashtable提供的哈希表)的性能。
  
在每个重写了equals方法的类中,你必须也要重写hashCode方法。如果不这样做的话,就会违反Object.hashCode的通用约定,从而导致该类无法与所有基于散列值(hash)的集合类结合在一起正常运行。
hashCode()的返回值和equals()的关系如下:
如果x.equals(y)返回“true”,那么x和y的hashCode()必须相等。 
如果x.equals(y)返回“false”,那么x和y的hashCode()有可能相等,也有可能不等。

3.重写equals()和hashcode()

为了使对象能够在逻辑上相等时equals方法能够返回true,我们来重写equals方法。

[java]  view plain  copy
  1. @Override  
  2. public boolean equals(Object obj) {  
  3.     //1. 自反性:对于任意的引用值x,x.equals(x)一定为true。  
  4.     if (this == obj)  
  5.         return true;  
  6.     //如果目标对象为空,则为false  
  7.     if (obj == null)  
  8.         return false;  
  9.     //如果两个对象不属于同一个类,则返回true  
  10.     if (getClass() != obj.getClass())  
  11.         return false;  
  12.     //将Object强转为Book  
  13.     Book other = (Book) obj;  
  14.     //对Book的两个属性进行比较,如果都完全相等,则返回true.  
  15.     if (name == null) {  
  16.         if (other.name != null)  
  17.             return false;  
  18.     } else if (!name.equals(other.name))  
  19.         return false;  
  20.     if (price != other.price)  
  21.         return false;  
  22.     return true;  
  23. }  

同时要重写hashcode方法:

[java]  view plain  copy
  1. @Override  
  2. public int hashCode() {  
  3.     final int prime = 31;  
  4.     int result = 1;  
  5.     result = prime * result + ((name == null) ? 0 : name.hashCode());  
  6.     result = prime * result + price;  
  7.     return result;  
  8. }  

在HashSet中测试重写的正确性:

[java]  view plain  copy
  1. Book book = new Book("java"11);  
  2. Book book1 = new Book("java"11);  
  3. HashSet<Book> set = new HashSet<Book>();  
  4. set.add(book);  
  5. set.add(book1);  
  6. System.out.println(set.size());  

HashSet中的存储时,会首先判断两个对象的hashcode值是否相等, 如果不相等,直接判断为不同的对象,就添加进去了,如果相等,再用equals方法进一步判断两个对象是否相等。

如没有重写equals方法和hashcode方法,以上代码的返回值是2,因为两个对象equals不等,所以HashSet把这两个对象当做不同的对象来处理,都会添加进去。

如果重写了equals方法而没有重写hashcode方法,返回值也是2,因为他们的hashcode方法可能不相等,HashSet直接就认为这两个对象不等,不进行equals判断了。

只有重写了equals方法和hashcode方法,返回值才为1,HashSet先进行hashcode判断,再进行equals判断,发现两个对象相等,认为这两个对象相等,就不会添加了。

特别注意:如果重写了这两个方法,在往HashSet中添加完值以后,就不能修改参与hash运算的字段了,因为一旦修改,由于HashSet是根据hash值来存储和获取对象的,我们将获取不到这个对象,会造成内存泄露。


转载自:http://blog.csdn.net/qq525201608/article/details/21238079

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值