Java中HashMap、HashSet中Object类型对象比较问题

在JAVA中使用HashMap和HashSet时,往往会考虑到key类型的问题。如果我们使用的key类型为java封装的基本类型(Integer、Double、String等)时,当两个key的内容相同时,他们在HashMap和HashSet中也会被认为是相同的。比如下面代码:

String s1 = new String("test");
String s2 = new String("test");
HashMap<String,Integer> map = new HashMap<String,Integer>(); 
HashSet<String> set = new HashSet<String>();

map.put(s1,1);
map.put(s2,1);

set.add(s1);
set.add(s2);

System.out.println("HashMap的大小:" + map.size());
System.out.println("HashSet的大小:" + set.size());

输出结果为:

HashMap的大小:1
HashSet的大小:1
其中s1和s2为String类型,且内容都为“test”,而HashMap和HashSet在添加s1、s2时,把它们识别为相同的key值,因此HashMap和HashSet的大小都为1。

但是,当我们把一个Object类型的对象作为HashMap和HashSet的key时,就会出现内容相同的对象被识别为不同key值的情况。比如以下代码:

public class Test {
	int a;

	public Test(int a) {
		super();
		this.a = a;
	}
	
	
	public static void main(String args[]){
		Test t1 = new Test(1);
		Test t2 = new Test(1);
		HashMap<Test,Integer> map = new HashMap<Test,Integer>(); 
		HashSet<Test> set = new HashSet<Test>();
		
		map.put(t1,1);
		map.put(t2,1);
		
		set.add(t1);
		set.add(t2);
		
		System.out.println("HashMap的大小:" + map.size());
		System.out.println("HashSet的大小:" + set.size());
				
	}
}

输出结果为:

HashMap的大小:2
HashSet的大小:2

可以看出,t1和t2虽然内容相同,有共同的成员a=1,但还是被HashMap和HashSet识别为不同的key值,这是为什么呢?

经过查看一些资料后,发现HashMap和HashSet中是通过key的hashCode来找key的位置,当我们创建一个对象时,其hashCode肯定是不同的,所以我们需要重写该对象的hashCode()方法,使得对象的hashCode跟其内容相关。比如以下代码:

public class Test {
	int a;

	public Test(int a) {
		super();
		this.a = a;
	}	
	
	@Override
	public int hashCode(){
		return a;
	} 
		
	public static void main(String args[]){
		Test t1 = new Test(1);
		Test t2 = new Test(1);
		HashMap<Test,Integer> map = new HashMap<Test,Integer>(); 
		HashSet<Test> set = new HashSet<Test>();
		
		map.put(t1,1);
		map.put(t2,1);
		
		set.add(t1);
		set.add(t2);
		
		System.out.println("HashMap的大小:" + map.size());
		System.out.println("HashSet的大小:" + set.size());
				
	}
}

输出结果仍然为:

HashMap的大小:2
HashSet的大小:2
我们将Test对象的hashCode改为其成员变量a的值,这样t1和t2的内容以及hashCode都相同了,但仍然无法被HashMap和HashSet识别为相同的key值。

又进行一阵摸索后,发现除了hashCode()方法外,equals()方法也有很大的作用,Integer、Double、String等都重写了Object的hashCode()和equals()方法,所以才能被HashMap和HashSet根据内容来识别。因此,我们来重写Test的equals()方法。

Java语言对equals()方法的要求如下,这些要求是必须遵循的:
• 对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。
• 反射性:x.equals(x)必须返回是“true”。
• 类推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”。
• 还有一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。
• 任何情况下,x.equals(null),永远返回是“false”;x.equals(和x不同类型的对象)永远返回是“false”。

比如以下代码:

public class Test {
	int a;

	public Test(int a) {
		super();
		this.a = a;
	}
		
	@Override
	public int hashCode(){
		return a;
	} 
	
	@Override
	public boolean equals(Object o){
		if(this.a == ((Test)o).a)
			return true;
		else
			return false;
	}
	
	public static void main(String args[]){
		Test t1 = new Test(1);
		Test t2 = new Test(1);
		HashMap<Test,Integer> map = new HashMap<Test,Integer>(); 
		HashSet<Test> set = new HashSet<Test>();
		
		map.put(t1,1);
		map.put(t2,1);
		
		set.add(t1);
		set.add(t2);
		
		System.out.println("HashMap的大小:" + map.size());
		System.out.println("HashSet的大小:" + set.size());
				
	}
}

输出得到了我们满意的结果:

HashMap的大小:1
HashSet的大小:1
这里,我们重写的equals()方法,只是简单地根据Test对象的成员变量a的值来比较大小。这样,HashMap和HashSet都把t1和t2识别为相同的key值。

以后当我们想往HashMap和HashSet中添加内容相同但不是指向同一内存地址的对象,但又不想有重复的对象时,就可以重写hashCode()和equals()方法解决。


最后注明一点:

equals()相等的两个对象,hashcode()一定相等;

equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值