`
ben.meng
  • 浏览: 11174 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

HashMap中重写hashCode和equals方法

阅读更多

原文地址:http://blog.chinaunix.net/u1/53616/showart_432480.html
我们可以放基本变量或者自己定义的对象来进行key-->value的查找

我们先创建一个自己的类,作为hashmap的key

class key {
		int i;
		public key(int i) {
			this.i = i;
		}
	}
	class value {
		int j;

		public value(int j) {
			this.j = j;
		}

		public String toString() {
			return "" + j;
		}
	}
	public class Test {
		public static void main(String[] args) {
			HashMap hm = new HashMap();
			key k = new key(1); // ******(1)
			value v = new value(2);
			hm.put(k, v);
			if (hm.containsKey(k)) // *********(2)
				System.out.println(hm.get(k)); // *********(3)
			else
				System.out.println("dont have such a key");
		}
	}


 
注意,我这里的hashmap中的key是自己new出一个对象,然后把对象的引用作为key的,这里突出了hashmap的查找原理,hashmap是通过key的hashcode来找到hashmap中的key,这里我在hashmap的key中是放一个对象的应用,我去拿key的时候也是通过这个引用,所以(1)处的key 与(2)、(3)处的key是完全一样的,所以这段程序没有任何问题,顺利运行。
现在我把测试类改一下:

	public class Test {
		public static void main(String[] args) {
			HashMap hm = new HashMap();

			hm.put(new key(1), new value(2));
			if (hm.containsKey(new key(1)))
				System.out.println(hm.get(new key(1)));
			else
				System.out.println("dont have such a key");
		}
	}

 注意区别,我这里hashmap中key放的不是引用,而是new出来的对象,然后我去get或者containsKey的时候也通过new一个key去拿,虽然我们初始化内容完全相同,都是放 int 1 进去,也就是说对象内容完全相同,但最后结果确实输出"dont have such a key"。

找原因,为什么内容相同,但找不到这个key呢,前面说了hashmap是通过hashcode来找key的位置,这是关键,你每次new 一个新对象出来hashcode肯定不一样,所以你拿不到你要的key。

解决方法,重写你编写的key类的hashcode方法。

class key {
		int i;

		public key(int i) {
			this.i = i;
		}

		@Override
		public boolean equals(Object obj) {
			if (obj instanceof key) {
				if (((key) obj).i == i)
					return true;
			}
			return false;
		}

		@Override
		public int hashCode() {
			return i;
		}
	}

  我们先不要看equals的重写,这里我们重写了hashcode这个方法,让它返回一个我们初始化进去的i,这样你每次new一个对象,因为是通过hashcode找key,而你的hashcode有只是值i,所以只要i相等,你就可以找到你的key的地址,注意,只是找到你要的key的地址,但key是不是同一个key还不一定。

然后我们开始比较我们传来的寻找value的key和hashmap中的key是不是同一个key,如果是那就找到了value。

在未重写equals方法我们是继承了object的equals方法,那里的 equals是比较两个对象的内存地址,显然我们new了2个对象内存地址肯定不一样,所以我们还要重写equals这个方法,让重写后的equals方法来比较我们对象里特有的东西。

重写equals方法一般按照如下步骤:
1.先判断这两个比较的对象是不是同个类型,如果类型都不相同,肯定不相同;
2.如果类型相同,我们先要把Object向下转型到我们的类类型,然后比较自己类特有的变量,这里我只是比较了类里i值是否相同,如果相同,则表明两个对象是相同的(只是作为hashmap的key来说是相同的),这样就可拿到hashmap的value了。

总结:
hashmap中value的查找是通过 key 的 hashcode 来查找,所以对自己的对象必须重写 hashcode 通过 hashcode 找到对对象后会用 equals 比较你传入的对象和 hashmap 中的 key 对象是否相同,所以要重写 equals.

//*******************

现在我们开始造假

因为前面说了hashmap是通过hashcode来找到key的位置,然后通过equals来比较key内容是否相同

那我们就可以做一个其它的类,但hashcode和equals和前面的key这个类完全相同

class key1 {
		int i;

		public key1(int i) {
			this.i = i;
		}

		@Override
		public boolean equals(Object obj) {
			if (obj instanceof key) {
				if (((key) obj).i == i)
					return true;
			}
			return false;
		}

		@Override
		public int hashCode() {
			return i;
		}
	}

  这样的话我在测试类Test中加上一句

public class Test {
	public static void main(String[] args) {
		HashMap hm = new HashMap();

		hm.put(new key(1), new value(2));
		hm.put(new key1(1), new value(22222222)); 
                        // ***这句是加的

		if (hm.containsKey(new key(1)))
			System.out.println(hm.get(new key(1)));
		else
			System.out.println("dont have such a key");
	}
}
  现在问题就来了,因为key1和key的hashcode定义都完全一样,就是说 new key(1) 和 new key1(1) 的hushcode完全一样,这样一来先定义的 new key(1) 就被后定义的 new key1(1) 覆盖了,但前面说了hashmap只是根据hashcode来找key位置,只要hushcode 一样就可以找到 key 的位置,所以我们是可以通过 new key(1) 来找到 new key1(1) 这个key的位置的,而且由于 key 类和 key1 类里的equals方法也一样,我们就可以用 new key(1)来假冒new key1(1) ,来拿到new key1(1) 对应的value值。

当然如果你想拿new value(2)这个value是肯定拿不到了
分享到:
评论

相关推荐

    equals 和 hashCode两者效果分析详解.docx

    原因是因为,在Java自带的容器HashMap和HashSet中, 都需同时要用到对象的hashCode()和equals()方法来进行判断,然后再插入删除元素,这点我们一会再谈。 那么我们还是单独来看hashCode(),为什么HashMap需要用到...

    Java equals 方法与hashcode 方法的深入解析

    面试时经常会问起字符串比较相关的问题,比如:字符串比较时用的什么方法,内部实现如何?hashcode的作用,以及重写equal方法,为什么要重写hashcode方法?以下就为大家解答,需要的朋友可以参考下

    HashTable和HashMap的区别_动力节点Java学院整理

    HashSet实现了Set接口,它不允许集合中有重复的值,当我们提到HashSet时,第一件事情就是在将对象存储在HashSet之前,要先确保对象重写equals()和hashCode()方法,这样才能比较对象的值是否相等,以确保set中没有...

    实验05 Java集合.doc

    注意:因为Person类是自定义类,需要重写hashCode()方法和equals()方法,并规定只有姓名和身份证号都相等,则对象相等。 其中计算哈希码的算法:(31 + ((name == null) ? 0 : name.hashCode()))*31 + id (注:...

    小白,和我一起学 HashMap 吗?

    equals() 必须重写 hashCode()7、TODO:8、常见面试题9、鸣谢 1、前言 本文主要讲解HashMap的底层数据结构、存取原理、扩容机制、线程安全性、java 7 和java 8版本的对比等方面。如果你正在学习HashMap,希望对你有...

    涵盖了90%以上的面试题

    为什么重写equals还要重写hashCode? 介绍一下volatile jdk1.5新特性 jdk1.7新特性 jdk1.8新特性 java语言有哪些优点? 同一个.java文件中是否可以有多个main方法 一个".java"源文件中是否可以包括多个类(不是内部类...

    HashSet和HashMap的区别_动力节点Java学院整理

    HashSet实现了Set接口,它不允许集合中有重复的值,当我们提到HashSet时,第一件事情就是在将对象存储在HashSet之前,要先确保对象重写equals()和hashCode()方法,这样才能比较对象的值是否相等,以确保set中没有...

    Java面试题.docx

    1、java中==和equals和hashCode的区别 2、int与integer的区别 3、String、StringBuffer、StringBuilder区别 4、什么是内部类?内部类的作用 5、进程和线程的区别 6、final,finally,finalize的区别 7、...

    Java面试经典题,对JAVA面试很有帮助

    7.重载和重写的区别 8.equals与==的区别 9.Hashcode的作用 10.String、String StringBuffer 和 StringBuilder 的区别是什 么? 11.ArrayList和linkedList的区别 12.HashMap和HashTable的区别 13.Collection包结构,与...

    安卓java读取网页源码-questions:自问自答

    父类的静态方法能否被子类重写 描述下类的加载机制 说说你对 Java 反射的理解 什么是动态代理 在 Java 中 wait、yield 和 seelp 方法的不同 描述下 Java 中的内存分配 什么是多态,实现多态的机制是什么 接口...

    leetcode题库-java-interview:Java研发基础相关

    重载与重写的区别 访问控制符 Object类方法 抽象类与接口 类初始化顺序 hashCode & equals == & equals this static 基本类型 & 包装类 String 泛型 内部类 集合类 ArrayList & LinkedList 详解 HashMap HashTable ...

    javaSE代码实例

    14.2.2 重写hashCode方法 275 14.3 集合框架的层次结构 -277 14.4 Ordered与Sorted的接口 278 14.4.1 Ordered的排序 278 14.4.2 Sorted的排序 279 14.5 列表 279 14.5.1 列表接口——st 279 14.5.2 ...

    安卓java读取网页源码-interview:安卓面试

    父类的静态方法能否被子类重写? 静态属性和静态方法是否可以被继承?是否可以被重写?为什么? 什么是内部类?内部类、静态内部类、局部内部类和匿名内部类的区别及作用? == 和 equals() 和 hashCode() 的区别? ...

    疯狂JAVA讲义

    学生提问:hashCode方法对于HashSet的作用是什么? 249 7.3.2 TreeSet类 252 7.3.3 EnumSet类 259 7.4 List接口 261 7.4.1 List接口和ListIterator接口 261 7.4.2 ArrayList和Vector实现类 264 7.4.3 固定长度...

    基于javatcpsocket通信的拆包和装包源码-java-interview:java基础知识点

    equals()&==&hashCode()&Object&hashMap String 和 StringBuffer的区别 Collection&Collections区别 hashSet如何保证不重复 什么是线程同步 进程 和 线程 Lock 和 Synchronized 的区别 常见的内存溢出 重载和重写的...

    ffmpeg-20170620-ae6f6d4-win64

    * 重写线程销毁方法,安全的关闭线程 */ @Override public void destroy() { status = false; } /** * 执行输出线程 */ @Override public void run() { String msg = ...

    Java学习笔记-个人整理的

    {2.2.2}方法重写/覆盖}{50}{subsection.2.2.2} {2.3}修饰符}{51}{section.2.3} {2.4}父类对象的方法调用}{51}{section.2.4} {2.5}封装}{52}{section.2.5} {2.6}多态}{53}{section.2.6} {2.7}Sample code}{54}...

Global site tag (gtag.js) - Google Analytics