1 package com.emsn.crazyjdk.java.util; 2 3 /** 4 * “人”类,重写了equals和hashcode方法...,以id来区分不同的人,你懂的... 5 * 6 * @author emsn1026 7 * 8 */ 9 10 public class Person { 11 12 /** 13 * 身份id 14 */ 15 private String id; 16 17 /** 18 * 姓名 19 */ 20 private String name; 21 22 public String getId() { 23 return id; 24 } 25 26 public void setId(String id) { 27 this.id = id; 28 } 29 30 public String getName() { 31 return name; 32 } 33 34 public void setName(String name) { 35 this.name = name; 36 } 37 38 @Override 39 public int hashCode() { 40 final int prime = 31; 41 int result = 1; 42 result = prime * result + ((id == null) ? 0 : id.hashCode()); 43 return result; 44 } 45 46 @Override 47 public boolean equals(Object obj) { 48 if (this == obj) 49 return true; 50 if (obj == null) 51 return false; 52 if (getClass() != obj.getClass()) 53 return false; 54 Person other = (Person) obj; 55 if (id == null) { 56 if (other.id != null) 57 return false; 58 } else if (!id.equals(other.id)) 59 return false; 60 return true; 61 } 62 63 @Override 64 public String toString() { 65 return "Person [id=" + id + ", name=" + name + "]"; 66 } 67 68 }
新建一个Person类,重写其中的equals和hashcode方法。这样,同样id的人会被认为是同样的事例,不同id的即时姓名相同也是不同的人,把Person类的实例作为HashMap的key时,key的唯一性讲通过Person实例的id来控制.
package com.emsn.crazyjdk.java.util; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import com.emsn.crazyjdk.java.util.Person; /** * @author emsn1026 * */ public class MapTest { /** * @param args */ public static void main(String[] args) { Map m = new HashMap(); Person p1 = new Person(); Person p2 = new Person(); p1.setId("1"); p1.setName("name1"); p2.setId("1"); p2.setName("name2"); m.put(p1, "person1"); m.put(p2, "person2"); System.out.println("Map m's size :" + m.size()); for(Object o :m.entrySet()){ Entry e = (Entry)o; System.out.println("key:"+ e.getKey()); System.out.println("value:"+ e.getValue()); } } }
打印的结果是
Map m's size :1
key:Person [id=1, name=name1]
value:person2
可见key已存在,value被覆盖,这个结果可以预测。那么接下来我们把代码修改下:
package com.emsn.crazyjdk.java.util; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import com.emsn.crazyjdk.java.util.Person; /** * @author emsn1026 * */ public class MapTest { /** * @param args */ public static void main(String[] args) { Map m = new HashMap(); Person p1 = new Person(); Person p2 = new Person(); p1.setId("1"); p1.setName("name1"); p2.setId("2"); p2.setName("name2"); m.put(p1, "person1"); m.put(p2, "person2"); System.out.println("Map m's size :" + m.size()); p2.setId("1"); System.out.println("Map m's size :" + m.size()); for(Object o :m.entrySet()){ Entry e = (Entry)o; System.out.println("key:"+ e.getKey()); System.out.println("value:"+ e.getValue()); } } }
此处的变化是将p1,p2的id设成不同,然后都作为key插入map,因为两个key不相同,所以我们的预测是都可以插入,此时map的size应该为2,待插入后我们修改p2的id为1,即与p1相同,这样就造成了两个entry的key相同的情况,测试再查看map的结构,看看是不是还是刚才插入的两项。
此时我们不知道HashMap的内部实现,所以我们不知道它的实例会不会在数据插入后还继续维持key的唯一性。
我们可以猜测的是三种答案:
1.抛出异常,不允许修改p2的id与p1相同,维护key的唯一性;
2.可以修改,但根据某种算法删除p1或p2中的一项,也能起到维护key的唯一性;
3.可以修改,没有任何事情发生....两项id相同的person实例并存于map中,即存在同一个key对应了两个value。
那么各位在没尝试并且没有查看过HashMap的源代码时会做出怎样的选择呢?
结果打印如下:
Map m's size :2
key:Person [id=1, name=name2]
value:person2
key:Person [id=1, name=name1]
value:person1
那么是预测的第三种情况...这原本不是我最看好的答案..这样我就有一个疑问了,既然可以有两个相同的key对应不同的value存在,那么我通过这个key应该拿到的value是哪个呢?在上述代码的main方法末尾加入以下两行代码:
System.out.println("Map m 通过get方法用key p1:"+p1+"时,获取的value:"+m.get(p1));
System.out.println("Map m 通过get方法用key p2:"+p2+"时,获取的value:"+m.get(p2));
得到的结果如下:
Map m 通过get方法用key p1:Person [id=1, name=name1]时,获取的value:person1
Map m 通过get方法用key p2:Person [id=1, name=name2]时,获取的value:person1
可见不论你使用p1还是p2,得到的value都是person1。
/** *jdk中get方法的源码 * Returns the value to which the specified key is mapped in this identity * hash map, or <tt>null</tt> if the map contains no mapping for this key. * A return value of <tt>null</tt> does not <i>necessarily</i> indicate * that the map contains no mapping for the key; it is also possible that * the map explicitly maps the key to <tt>null</tt>. The * <tt>containsKey</tt> method may be used to distinguish these two cases. * * @param key the key whose associated value is to be returned. * @return the value to which this map maps the specified key, or * <tt>null</tt> if the map contains no mapping for this key. * @see #put(Object, Object) */ public V get(Object key) { if (key == null) return getForNullKey(); int hash = hash(key.hashCode()); for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value;//--关键在这里。 } return null; }
如果一个Key对应2个Value。 他按顺序找到后,直接就 Return a.value了。而不会循环Person2.