以前一直只听某些所谓的高人经常说什么“那就重写equals方法嘛”或者“XXX 条件下,要重写equals方法”啊什么的论语。但自己从来没有看见过,理解过其中的究竟。也从来没有写过。更不知道在什么时候可以用,以及怎么用。原来发现人参泡在“自己不知道自己不明白”的杯具中。
现归结以前一直不明白的问题如下:
Q1:为什么要重写equals和HashCode?
Q2:如果重写了上述2个方法,那么究竟是修改了哪个对象的equals和hashCode方法?
Q3:equals方法中的return int 和hashCode方法中的 return boolean 这2个返回值到底是什么意思? 有什么意义? 如果返回值不同会导致什么样的结果?
Q4:equals方法和hashCode方法调用的顺序是怎样的? 以及2个方法被调用的时机? 2个方法会不会有可能不被调用?或者必须2者中的某一个是不是一定会被调用? 等等
通过老大的指点,现通过一个简单案例和图片来回答以上4个问题:
测试案例情形:
将对象 User 放到集合SET里去,然后打印SET集合的对象的数量是多少。
Part 1 代码:
分析:
L1:首先在内存块堆中给users划分一块空间地址比如a1,再栈中给对象new HashSet划分一块空间比如地址a2。a1指向a2。
L2:同理user--->b1 ;new User("lisa","ddd")---->b2; b1---->b2.
L3: 将user加入到 users中。即将b1 加入到a2中。
在加入的过程中,即调用 hashcode()方法将对象user灌到users中去,而这里的return 1.即理解为set为一栋大楼,而1则为大楼中的第一个房间,而这里即是把user对象放到大楼里面的第一个房间里面去存起。
于是打印了“fn ----> hashCode”。
接着打印 size---->1
但这里为什么只打印了fn ----> hashCode 和 size---->1,而没有打印fn ----> equals 呢?
那就要从hashSet的理解开始了:
首先大家知道hashSet默认是不能放重复的对象到它里面去,hashCode就是负责将对象怎样放在set里面去,而equals()方法就是负责判断你前后放进的对象是否是“重复”的。
那所谓的“重复”又是什么意思呢? 重复就是根据你的业务来判断了。
打个比方:
(1)公安机关认为只要某人的身份证号是一样的,那就是同一个人,不管你是男是女还是李宇春,或者长得美丑或像宋祖德。只要身份证是同一个号码,我公安机关就认定你是同一个人。
(2)但对于普通老百姓就不这样认为了,我不仅要你身份证号码是一样的,还要求你那张脸一定要是李宇春那张脸的,我才认为是同一个人,至少春迷是这样认为的。
所以重复就是不同的业务来定义,对不对。那么就要用到equals 方法来作为人们的判断条件了。因此如果我们要根据不同的业务来判断一个对象是不是同一个对象,就需要我们重写该对象的hashCode和 equals 方法了。对不对。我们这里是判断User对象,因此就重写了User对象的hashCode和 equals 方法.因此这里就回答了Q1和Q2 了。
继续 初始时SET里面为空,因此程序就只负责将user灌到users中,而不用去比较了,因为没有比较的对象啊。所以就没有调用 equals 方法了,因此就没有打印 fn----->equals 了。
感谢--徐老师
继续见 重写equals 和hashCode 探解之洗洗脚(二)
现归结以前一直不明白的问题如下:
Q1:为什么要重写equals和HashCode?
Q2:如果重写了上述2个方法,那么究竟是修改了哪个对象的equals和hashCode方法?
Q3:equals方法中的return int 和hashCode方法中的 return boolean 这2个返回值到底是什么意思? 有什么意义? 如果返回值不同会导致什么样的结果?
Q4:equals方法和hashCode方法调用的顺序是怎样的? 以及2个方法被调用的时机? 2个方法会不会有可能不被调用?或者必须2者中的某一个是不是一定会被调用? 等等
通过老大的指点,现通过一个简单案例和图片来回答以上4个问题:
测试案例情形:
将对象 User 放到集合SET里去,然后打印SET集合的对象的数量是多少。
Part 1 代码:
public class User{
public String userName;
public String password;
public User(String userName,String password){
this.userName = userName;
this.password = password;
}
public static void main(String[] arg){
Set<User> users = new HashSet<User>(); //L1
User user=new User("lisa","ddd"); //L2
users.add(user); //L3
// User user1=new User("lisa","ddd"); //L4
// users.add(user1); //L5
System.out.println(“size---->"+users.size()); //L6
}
//重写hashCode和equals方法
public int hashCode(){
system.out.println("fn ----> hashCode");
return 1;
}
public boolean equals(){
system.out.println("fn ----> equals");
return true;
}
}
执行结果:
fn ----> hashCode
size---->1
分析:
L1:首先在内存块堆中给users划分一块空间地址比如a1,再栈中给对象new HashSet划分一块空间比如地址a2。a1指向a2。
L2:同理user--->b1 ;new User("lisa","ddd")---->b2; b1---->b2.
L3: 将user加入到 users中。即将b1 加入到a2中。
在加入的过程中,即调用 hashcode()方法将对象user灌到users中去,而这里的return 1.即理解为set为一栋大楼,而1则为大楼中的第一个房间,而这里即是把user对象放到大楼里面的第一个房间里面去存起。
于是打印了“fn ----> hashCode”。
接着打印 size---->1
但这里为什么只打印了fn ----> hashCode 和 size---->1,而没有打印fn ----> equals 呢?
那就要从hashSet的理解开始了:
首先大家知道hashSet默认是不能放重复的对象到它里面去,hashCode就是负责将对象怎样放在set里面去,而equals()方法就是负责判断你前后放进的对象是否是“重复”的。
那所谓的“重复”又是什么意思呢? 重复就是根据你的业务来判断了。
打个比方:
(1)公安机关认为只要某人的身份证号是一样的,那就是同一个人,不管你是男是女还是李宇春,或者长得美丑或像宋祖德。只要身份证是同一个号码,我公安机关就认定你是同一个人。
(2)但对于普通老百姓就不这样认为了,我不仅要你身份证号码是一样的,还要求你那张脸一定要是李宇春那张脸的,我才认为是同一个人,至少春迷是这样认为的。
所以重复就是不同的业务来定义,对不对。那么就要用到equals 方法来作为人们的判断条件了。因此如果我们要根据不同的业务来判断一个对象是不是同一个对象,就需要我们重写该对象的hashCode和 equals 方法了。对不对。我们这里是判断User对象,因此就重写了User对象的hashCode和 equals 方法.因此这里就回答了Q1和Q2 了。
继续 初始时SET里面为空,因此程序就只负责将user灌到users中,而不用去比较了,因为没有比较的对象啊。所以就没有调用 equals 方法了,因此就没有打印 fn----->equals 了。
感谢--徐老师
继续见 重写equals 和hashCode 探解之洗洗脚(二)