最近 被 某某跟某某是否相等 给搞混了。。什么物理地址 哈希值 对象的 引用 巴拉巴拉一大堆 。。
先上几个结论 让没有时间的猿类 直接知道答案好了。:
结论就是:
1。如果两个对象相同(a.equlas(b)),那么它们的hashCode值一定要相同;
2。如果两个对象的hashCode相同,它们并不一定相同 (有何能a.equals(b)为false)
关于(==)
如果是 单纯的数据类型的比较 就只是比较值是否相同
如果是类对象 对象引用的比较就是 比较 他们在内存中的地址 值是否相同。。
hashcode()的默认值是内存地址 == 符号两端 尽享判断的 也是内存地址 。。只是 如果hashcode被重写了。就不一定是内存地址了。
(1)如果是基本类型比较,那么只能用:==来比较,不能用equals
(2)对于基本类型的包装类型,比如Boolean、Character、Byte、Shot、Integer、Long、Float、Double等的引用变量,==是比较地址的,而equals是比较内容的
一类是List ---集合内的元素是有序的,元素可以重复
一类是Set ---元素无序,但元素不可重复
那么问题来了:怎么判断他们不重复呢? 总用equlas()太麻烦了。。如果有100000个数据,添加第100001个。就要判断100000次。那估计的死了,所以 hashcode就来了。
hashcode
是object的方法 他默认的就是 内存地址 所有事物都继承了Object所以都有 hashcode方法。 就是为了存数据更快一些。。
怎么快得呢?
java存东西 先看 hashcode 如果这个相同 再判断 equals() 如果再在相同就 代表两个 是一个东西 就不存了因为内存里面已经有了 没必要再存了
如果equals()不同 那么就保存 ,具体保存到哪呢(网上说什么的都有,反正他们返回的hashcode()是一样的)。
这样就大大降低了 效率 面的每个都去查找
equals
也是 object的方法 。
public boolean equals(Object obj) {
return (this == obj);
}
也是使用了 (==) 这个符号。。就是看这两个的地址是否相同。。这是 Object类中的方法
但是其他方法都会 重写object方法。所以呢 equlas()就是判断 内存中这两个 类 或者是内容 是否相同。。
equals 方法在非空对象引用上实现相等关系: (感觉面试会用到。)
自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。
一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
对于任何非空引用值 x,x.equals(null) 都应返回 false。
下面是代码:
public static void main(String args[]){
String s1=new String("zhaoxudong");
String s2=new String("zhaoxudong");
System.out.println(s1==s2);//false
System.out.println(s1.equals(s2));//true
System.out.println(s1.hashCode());//s1.hashcode()等于s2.hashcode()
System.out.println(s2.hashCode());
Set hashset=new HashSet();
hashset.add(s1);
hashset.add(s2);
/*实质上在添加s1,s2时,运用上面说到的两点准则,可以知道hashset认为s1和s2是相等的,是在添加重复元素,所以让s2覆盖了s1;*/
Iterator it=hashset.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
最后在while循环的时候只打印出了一个”zhaoxudong”。 输出结果为:false
true
-967303459
-967303459
这是因为String类已经重写了equals()方法和hashcode()方法,
所以在根据上面的第1.2条原则判定时,hashset认为它们是相等的对象,进行了重复添加。
import java.util.*;
public class HashSetTest {
public static void main(String[] args)
{
HashSet hs=new HashSet();
hs.add(new Student(1,"zhangsan"));
hs.add(new Student(2,"lisi"));
hs.add(new Student(3,"wangwu"));
hs.add(new Student(1,"zhangsan"));
Iterator it=hs.iterator();
while(it.hasNext())
}
{
System.out.println(it.next());
}
}
}
class Student
{
int num;
String name;
Student(int num,String name)
{ this.num=num;
this.name=name;
}
public String toString()
{ return num+":"+name;
}
}
输出结果为:
1:zhangsan
1:zhangsan
3:wangwu
2:lisi
问题出现了,为什么hashset添加了相等的元素呢,
这是不是和hashset的原则违背了呢?
回答是:
没有 因为在根据hashcode()对两次建立的new Student(1,"zhangsan")对象进行比较时,生成的是不同的哈希码值,所以hashset把他当作不同的对象对待了,当然此时的equals()方法返回的值也不等(这个不用解释了吧)。那么为什么会生成不同的哈希码值呢?上面我们在比较s1和s2的时候不是生成了同样的哈希码吗?原因就在于我们自己写的Student类并没有重新自己的hashcode()和equals()方法,所以在比较时,是继承的object类中的hashcode()方法,它是一个本地方法,比较的是对象的地址(引用地址),使用new方法创建对象,两次生成的当然是不同的对象了(这个大家都能理解吧。。。),造成的结果就是两个对象的hashcode()返回的值不一样。所以根据第一个准则,hashset会把它们当作不同的对象对待,自然也用不着第二个准则进行判定了。那么怎么解决这个问题呢??
答案是:在Student类中重新hashcode()和equals()方法。/
class Student {
int num;
String name;
Student(int num,String name)
{this.num=num;
this.name=name;
}
public int hashCode() {
return num*name.hashCode();
}
public boolean equals(Object o) {
Student s=(Student)o;
return num==s.num && name.equals(s.name);
}
public String toString() {
return num+":"+name;
}
}
根据重写的方法,即便两次调用了new Student(1,"zhangsan"),
我们在获得对象的哈希码时,根据重写的方法hashcode(),
获得的哈希码肯定是一样的(这一点应该没有疑问吧)。
当然根据equals()方法我们也可判断是相同的。
所以在向hashset集合中添加时把它们当作重复元素看待了。
所以运行修改后的程序时,我们会发现运行结果是:
1:zhangsan
3:wangwu
2:lisi
可以看到重复元素的问题已经消除
下面是equlas()和 == 的关系
String s1 = "123";
String s2 = "123";
String s3 = "abc";
String s4 = new String("123");
String s5 = new String("123");
String s6 = new String("abc");
System.out.println(s1 == s2);// (1)true
System.out.println(s1.equals(s2));// (2)true
System.out.println(s1 == s3);// (3)flase
System.out.println(s1.equals(s3));// (4)flase
System.out.println(s4 == s5);// (5)flase
System.out.println(s4.equals(s5));// (6)true
System.out.println(s4 == s6);// (7)flase
System.out.println(s4.equals(s6));// (8)flase
System.out.println(s1 == s4);// (9)false
System.out.println(s1.equals(s4));// (10)true
String s2 = "123";
这一句会把数据放到一个常量池中,,这个里面的数据也都不一样 如果一样 所以 两个引用s1和s2 都指向“123” 所以他们的引用地址 是一样的。。所以是true
后面留给观众 去思考了。。
我也是在网上各种百度各种尝试 总结的。也找不到出处了。。总之是感谢 大神们的分享 。。