深入浅出Java中的==,equals(), hashCode()

前言-----

==,equals(), hashCode()是不是傻傻分不清, 相信我,  看完这篇博客就不会了

目录

测试类

一. 快速区分 ==和equals()的区别

二.如何把ID和Brand相同的car判定为同一对象呢?

三.什么是hashCode值

四.hashCode值的比较结果 和 equals()的比较结果在逻辑上应该一致

五.equals()和hashCode()重写时的注意事项


测试类

class Car{
	
	
	String ID;//车牌号
	String Brand;//品牌
        String mileage //行驶的公里数
	
	public Car(String ID,String Brand) {
		
		this.ID = ID;
		this.Brand = Brand;
	}
}

 

一. 快速区分 ==和equals()的区别

  • ==是判断两个对象的地址是否相同
  • equals()方法如果没有重写的话,默认也是调用==方法进行比较

   

package Test;

import java.util.HashMap;

public class HashMapTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		Car car1 = new Car("1222","AA");
		Car car2 = new Car("1222","AA");
		
		
		System.out.println(car1 == car2);
		
		System.out.println(car1.equals(car2));
    }
}

测试结果:

由于car1和car2在在内存中的地址不相同,所以测试结果都是false

二.如何把ID和Brand相同的car判定为同一对象呢?

有时,我们需要根据对象的属性值来判断对象是否相同,而不是仅仅从对象的地址来判断, 那么如何做到呢?重写equals()函数,

String 中用equals()比较字符串内容否相同,本质上也是因为重写了Object类中的equals()方法:

现在我们重写Car类的equals()方法, 只要ID和Brand相同,就视为同一个对象:

package Test;

import java.util.HashMap;

public class HashMapTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		Car car1 = new Car("1222","AA");
		Car car2 = new Car("1222","AA");
		
		
		System.out.println(car1 == car2);
		
		System.out.println(car1.equals(car2));
		
	}
}

class Car{
	
	
	String ID;//车牌号
	String Brand;//品牌
        String mileage //行驶的公里数
	
	public Car(String ID,String Brand) {
		
		this.ID = ID;
		this.Brand = Brand;
	}


	public boolean equals(Object obj) { //定义ID和Brand都相同的对象就是相同的
		
		return   (ID ==((Car)obj).ID ) && (Brand ==((Car)obj).Brand);
	}
}

此时测试结果是false 和true, 说明equals()已经改写咯

三.什么是hashCode值

如果把对象类比为一个学生,那么对象的地址相当于学生的身份证,是独一无二的;  而hashCode值相当于一个学生的姓名,可能会有多个对象拥有相同的hashCode值, 如同姓名相同.

package Test;

import java.util.HashMap;

public class HashMapTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		Car car1 = new Car("1222","AA");
		Car car2 = new Car("1222","AA");
		
		
		System.out.println(car1.hashCode());
		System.out.println(car2.hashCode());
   }
}

class Car{
	
	
	String ID;//车牌号
	String Brand;//品牌
        String mileage //行驶的公里数
	
	public Car(String ID,String Brand) {
		
		this.ID = ID;
		this.Brand = Brand;
	}


	public boolean equals(Object obj) { //定义ID和Brand都相同的对象就是相同的
		
		return   (ID ==((Car)obj).ID ) && (Brand ==((Car)obj).Brand);
	}
}

测试结果:

car1的hashCode值为:2018699554
car2的hashCode值为: 1311053135

四.hashCode值的比较结果 和 equals()的比较结果在逻辑上应该一致

  • 为什么要一致?

还是以上面的car1和car2为例, 我们重写了equals()的方法,car1.equals(car2)的结果true, 但是car1和car2的hashCode值却不同,用hashCode值判是否相同的话,结果会是false, 二者的结果是不相同的.  这在逻辑上是说不过去的, 所以我们应该另hashCode值的比较结果和equals()的比较结果在逻辑上一致 ,这也是一个良好的习惯.

  • 那么如何另二者的比较结果一致呢?

重写hashCode方法,且必须设计一种生成机制, 在这种机制下,ID 和Brand的Car对象可以拥有相同的hashCod值, 不妨设计如下:

	public int hashCode() {
		
		return ID.hashCode() + Brand.hashCode();
		
	}

测试demo:

import java.util.HashMap;

public class HashMapTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		Car car1 = new Car("1222","AA");
		Car car2 = new Car("1222","AA");
		
		
		System.out.println("car1的hashCode值为:" +car1.hashCode());
		System.out.println("car2的hashCode值为:" +car2.hashCode());
		
		System.out.print("用equals()的比较结果是:");
		System.out.println( car1.equals(car2) );
		
		 System.out.print("用hashCode值的比较结果是:" );
		 System.out.println( car1.hashCode()==car2.hashCode() );
    }
}

class Car{
	
	
	String ID;//车牌号
	String Brand;//品牌
        String mileage //行驶的公里数
	
	public Car(String ID,String Brand) {
		
		this.ID = ID;
		this.Brand = Brand;
	}


	public boolean equals(Object obj) { //定义ID和Brand都相同的对象就是相同的
		
		return   (ID ==((Car)obj).ID ) && (Brand ==((Car)obj).Brand);
	}
	

	public int hashCode() {
		
		return ID.hashCode() + Brand.hashCode();
		
	}
	
	
	
}

测试结果:

car1的hashCode值为:1511489
car2的hashCode值为:1511489
用equals()的比较结果是:true
用hashCode值的比较结果是:true

五.equals()和hashCode()重写时的注意事项

注:此段内容参考了该博客,感谢

  • 在程序执行期间,只要equals方法的比较操作用到的信息没有被修改,那么对这同一个对象调用多次,hashCode方法必须始终如一地返回同一个整数。
  • 如果两个对象根据equals方法比较是相等的,那么调用两个对象的hashCode方法必须返回相同的整数结果。
  • 如果两个对象根据equals方法比较是不等的,则hashCode方法不一定得返回不同的整数。

第二条的内容就是上面我所解释的.

第三条的内容也好理解, 如果equals()结果是不等, 但是hashCode值有小概率是相等的.

第一条的内容: 就是说hashCode() 里面用于生成hashCode的字段最好是不容易改变的 ,以上面重写的hashCode()方法为例.

	public int hashCode() {
		
		return ID.hashCode() + Brand.hashCode();
		
	}

这边hashCode值依靠于Car的ID和Brand这两个属性, 如果某个时候, ID或者Brand改变了,那么对于的hashCode值也会改变了,

这又有什么影响呢,不妨看段代码:

package Test;

import java.util.HashMap;

public class HashMapTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub


		HashMap <Car, String> myMap = new HashMap <Car,String>();
		
		Car car1 = new Car("1222","AA");
		
		System.out.print("此时的hashCode值为:");
		System.out.println(car1.hashCode());
		
		myMap.put(car1, "Jane");
		
		
		car1.ID = "1111";
		System.out.print("修改ID后,hashCode值为:");
		System.out.println(car1.hashCode());

		
		//判断是否存在key为car1的Entry
		System.out.println(myMap.get(car1)); 

		

	}
	

}
class Car{
	
	
	String ID;//车牌号
	String Brand;//品牌
        String mileage //行驶的公里数
	
	public Car(String ID,String Brand) {
		
		this.ID = ID;
		this.Brand = Brand;
	}


	public boolean equals(Object obj) { //定义ID和Brand都相同的对象就是相同的
		
		return   (ID ==((Car)obj).ID ) && (Brand ==((Car)obj).Brand);
	}
	

	public int hashCode() {
		
		return ID.hashCode() + Brand.hashCode();
		
	}
	
	
	
}

测试结果:

此时的hashCode值为:1511489
修改ID后,hashCode值为:1510496
null
 

熟悉HashMap的朋友应该很清楚,  HashMap中的get()方法是通过比较hash值来查找的,而hash值又依赖于hashCode值,因此就不难理解为什么结果是null了. 因为HashMap中car1的hashCode值和 修改ID后的car1的hashCode值不同了

为了尽量避免这种情况, 用于生成hashCode()的字段在使用过程中应该是比较不会频繁更改的字段, 所以这也是为什么不用 mileage (行驶的公里数)来生成hashCode值的原因了, 它更容易被更改.

猜你喜欢

转载自blog.csdn.net/CCSGTC/article/details/84344111