这篇文章讲一下这3个的知识点,需要对java执行过程中内存过程有点了解,可以看看上一篇文章程序执行过程的内存分析
UserBean类
public class UserBean {
private String name;
private int age;
private String sex;
private int height;
public UserBean(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
UserBean user1=new UserBean();
UserBean user2=new UserBean();
System.out.println(user1==user2);
System.out.println(user1.equals(user2));
运行结果:false false
我们先看一下equals的源码:
public boolean equals(Object obj) {
return (this == obj);
}
而==看的是user1和user2的地址,很显然,二者地址不一样,所有都是false。
如果我们想有自己的比较方式,不想比较地址值,想比较name是否相同,从而判断两个user是否一样,我们应该重写equals方法
@Override
public boolean equals(Object obj) {
UserBean bean = (UserBean) obj;
return this.name == bean.name;
}
这样运行的结果是:false true
hashCode
在讲hashCode之前,先看一段代码:
HashSet hashSet = new HashSet();
hashSet.add(new UserBean("a1", 22));
hashSet.add(new UserBean("a2", 23));
hashSet.add(new UserBean("a3", 24));
hashSet.add(new UserBean("a1", 22));
Iterator iterator = hashSet.iterator();
while (iterator.hasNext()) {
UserBean userBean = (UserBean) iterator.next();
System.out.println("name:" + userBean.getName() + " age:" + userBean.getAge());
}
打印的结果:
name:a2 age:23
name:a1 age:22
name:a1 age:22
name:a3 age:24
(图片下面再解释)
可以看出1.HashSet没有顺序 2.name为a1 age为22的两个数据应该是重复了,但是还是被添加了进来。。。。。。。我们难道应该重写equals?来判断两个对象是否一样,如果一样,就不添加。
@Override
public boolean equals(Object obj) {
UserBean userBean = (UserBean) obj;
System.out.println(this.name + "....equals..." + userBean.name);
return this.name == userBean.name && this.age == userBean.age;
}
重写方法后,运行依旧没有 System.out.println(this.name + "....equals..." + userBean.name);打印这个,说明没有走equals方法,这个时候就需要hashcode登场了。
public int hashCode() {
System.out.println("...hascode...");
return 60;
}
public boolean equals(Object obj) {
UserBean userBean = (UserBean) obj;
System.out.println(this.name + "....equals..." + userBean.name);
return this.name == userBean.name && this.age == userBean.age;
}
打印结果:
...hascode...
...hascode...
a2....equals...a1
...hascode...
a3....equals...a1
a3....equals...a2
...hascode...
a1....equals...a1
name:a1 age:22
name:a2 age:23
name:a3 age:24
在hash表中,1先进来(给个hashcode),2再次进来,hashcode和1的值一样,在判断name和age(二者不一样),得出1和2是两个值,所以把2添加进来,这是因为2和1的hashcode值一样,所以把2挂到1上去。以此类推,最后一个值重复了,所以不添加。
从效率上来考虑,每次进来都要hashcode 和equals,有点复杂,我们可以根据业务需求,自己建立值,能提高效率
public int hashCode() {
System.out.println("...hascode...");
return name.hashCode()+age*36;
}
public boolean equals(Object obj) {
UserBean userBean = (UserBean) obj;
System.out.println(this.name + "....equals..." + userBean.name);
return this.name == userBean.name && this.age == userBean.age;
}
打印结果:(只比较了一次)
...hascode...
...hascode...
...hascode...
...hascode...
a1....equals...a1
name:a3 age:24
name:a1 age:22
name:a2 age:23
总结:HashSet怎么能确保数据的唯一性??
通过hascode和equals,如果hascode元素相同,才会判断equals是否为true,如果hashcode不同,不会调用equals。