详细解释 hashcode equals() "==" 的区别和联系



最近 被  某某跟某某是否相等 给搞混了。。什么物理地址  哈希值   对象的 引用 巴拉巴拉一大堆 。。
先上几个结论  让没有时间的猿类 直接知道答案好了。:


结论就是:
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是比较内容的


Java中的集合(Collection)有两类,
一类是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

后面留给观众 去思考了。。

我也是在网上各种百度各种尝试 总结的。也找不到出处了。。总之是感谢 大神们的分享 。。




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值