A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 何仕映 于 2013-4-19 15:56 编辑

在Map集合中,jvm是通过什么方法去判断键值的呢?那个方法又是怎么调用的呢?
比如在下面这个程序中,mymap.put("05","ZHM");和mymap.put("05","zh");这两个语句。jvm是怎么去这两个"05"的键值的呢?调用的什么方法比较的?调用的过程是什么呢?求大神解答。
  1. import java.util.*;
  2. class MyMap
  3. {
  4.         public static void main(String[] args)
  5.         {
  6.                 Map<String,String> mymap = new HashMap<String,String>();//定义一个Map集合
  7.                 //向集合中添加元素
  8.                 /*
  9.                 1.通过put方法存元素的时候,返回值是该键之前对应的值
  10.                 2.在HashMap中null可以当作键值或者Value值存在。
  11.                 */
  12.                 sop(mymap.put("01","Zhanghongmei"));
  13.                 sop(mymap.put("01","Zhanghongmei1"));
  14.                 mymap.put("02","ZHM");
  15.                 mymap.put("03","meimei");
  16.                 mymap.put("05","ZHM");
  17.                 mymap.put("05","zh");
  18.                 mymap.put("04",null);
  19.                 mymap.put(null,"MM");
  20.                
  21.                 //判断集合中是否存在指定键或者指定值
  22.                 sop("mymap是否存在键值03:"+mymap.containsKey("03"));
  23.                 sop("mymap是否存在值ZHM:"+mymap.containsValue("ZHM"));
  24.                 sop("mymapz中是否存在键值003:"+mymap.containsKey("003"));
  25.                 sop("mymap中是否存在值ZHMx:"+mymap.containsValue("ZHMx"));
  26.                
  27.                 //通过values方法,把集合中value值,取出。并存储在一个Collection集合中,返回该集合。
  28.                 sop("mymap中所有的值是:"+mymap.values());
  29.         }

  30.         public static<E> void sop(E e)
  31.         {
  32.                 System.out.println(e);
  33.         }
  34. }
复制代码

7 个回复

倒序浏览
利用默认Hashcode算法来区分键和值是否相同,如果是自定义对象就按照复写的HashCode来进行判断。
回复 使用道具 举报
梁航斌 发表于 2013-4-19 15:30
利用默认Hashcode算法来区分键和值是否相同,如果是自定义对象就按照复写的HashCode来进行判断。 ...

如果是利用hashCode方法来判断键值是否相同,那么在下面这个程序中,打印的结果应该只有一个对象啊。
下面这个程序是毕老师的上课时讲的一个程序,我把hashCode方法改了,返回值都是1。按照您说的是通过hashCode方法来比较键值,那么这几个键值应该都相同啊。但是运行的结果为什么还是5个对象呢?
  1. import java.util.*;
  2. class Student implements Comparable<Student>
  3. {
  4.         private String name;
  5.         private int age;
  6.         Student(String name,int age)
  7.         {
  8.                 this.name = name;
  9.                 this.age = age;
  10.         }
  11.        
  12.         public int compareTo(Student s)
  13.         {
  14.                 int num = new Integer(this.age).compareTo(new Integer(s.age));

  15.                 if(num==0)
  16.                         return this.name.compareTo(s.name);
  17.                 return num;
  18.         }

  19. <font color="#ff0000">        public int hashCode() //复写hashCode方法</font>
  20.         {
  21.                 return 1;
  22. //                return name.hashCode()+age*34;
  23.         }
  24.         public boolean equals(Object obj)
  25.         {
  26.                 if(!(obj instanceof Student))
  27.                         throw new ClassCastException("类型不匹配");

  28.                 Student s = (Student)obj;

  29.                 return this.name.equals(s.name) && this.age==s.age;
  30.                

  31.         }
  32.         public String getName()
  33.         {
  34.                 return name;
  35.         }
  36.         public int getAge()
  37.         {
  38.                 return age;
  39.         }
  40.         public String toString()
  41.         {
  42.                 return name+":"+age;
  43.         }
  44. }



  45. class  MapTest
  46. {
  47.         public static void main(String[] args)
  48.         {
  49.                 HashMap<Student,String> hm = new HashMap<Student,String>();

  50.                 hm.put(new Student("lisi1",21),"beijing");
  51.                 hm.put(new Student("lisi1",21),"tianjin");
  52.                 hm.put(new Student("lisi2",22),"shanghai");
  53.                 hm.put(new Student("lisi3",23),"nanjing");
  54.                 hm.put(new Student("lisi4",24),"wuhan");


  55.                 //第二种取出方式 entrySet
  56.                 Set<Map.Entry<Student,String>> entrySet = hm.entrySet();

  57.                 Iterator<Map.Entry<Student,String>> iter = entrySet.iterator();
  58.                
  59.                 while(iter.hasNext())
  60.                 {
  61.                         Map.Entry<Student,String> me = iter.next();
  62.                         Student stu = me.getKey();
  63.                         String addr = me.getValue();
  64.                         System.out.println(stu+"........."+addr);
  65.                 }
  66.         }
  67. }
复制代码
回复 使用道具 举报
本帖最后由 HM朱蛟 于 2013-4-19 15:50 编辑

楼主你好,我说下我的看法,不对的请指出,认真学习,共同提高。

笔记:
|--HashMap:底层是哈希表数据结构,允许使用 null 值和 null 键,该集合是不同步的。将hashtable替代,jdk1.2.效率高。
|--TreeMap:底层是二叉树数据结构。线程不同步。可以用于给map集合中的键进行排序。

思路:
Set集合底层是调用的Map集合
HashMap对应的应该是HashSet,数据结构是哈希表,先比hashCode(),再比equals。
TreeMap对应的是TreeSet,数据结构是二叉树,依据compareTo的返回值(为0时)来保证元素唯一性。

代码:(取键值,要么把键导入Set集合,要么把映射关系导入set集合,我认为这实际上还是单个元素在作比较)
  1. /*
  2. 需求:
  3. 每一个学生都有对应的归属地。
  4. 学生student,地址string。
  5. 学生属性:姓名,年龄。
  6. 注意:姓名和年龄相同的视为同一个学生。保证学生的唯一性。
  7. */

  8. import java.util.*;

  9. class Student implements Comparable<Student>
  10. {
  11.         private String name;
  12.         private int age;
  13.         Student(String name,int age)
  14.         {
  15.                 this.name = name;
  16.                 this.age = age;
  17.         }
  18.         
  19.         public int compareTo(Student s)
  20.         {
  21.                 int num = new Integer(this.age).compareTo(new Integer(s.age));
  22.                
  23.                 if(num==0)
  24.                   return this.name.compareTo(s.name);
  25.                
  26.                 return        num;
  27.         }

  28.         public int hashCode()//散列算法
  29.         {
  30.                 return this.name.hashCode()+this.age*34;
  31.         }
  32.         
  33.         public boolean equals(Object obj)//必须要有2个元素才具备自动调用该方法的前提,并且这里不能指定泛型
  34.         {
  35.                 if(!(obj instanceof Student))//若传进来的不是student类
  36.                   throw new ClassCastException("类型转换异常"); //直接报异常
  37.                
  38.                 Student s = (Student)obj;
  39.                
  40.                 return this.name.equals(s.name) && this.age==s.age;
  41.         }
  42.         
  43.         public String getName()
  44.         {
  45.     return name;        
  46.         }

  47.         public int getAge()
  48.         {
  49.           return age;        
  50.         }
  51.         
  52.         public String toString()
  53.         {
  54.                 //return this.getName()+"..."+this.getAge();
  55.                 return this.name+".."+this.age;
  56.         }
  57. }

  58. //取出方式1:keySet()
  59. class MapTestKS
  60. {
  61.         public static void main(String[] args)
  62.         {
  63.                 HashMap<Student,String> map = new HashMap<Student,String>();
  64.                
  65.                 map.put(new Student("haha-1",1),"beijing");
  66.                 //System.out.println(map.put(new Student("haha-1",1),"nanjing"));//put返回被覆盖的值 beijing
  67.                 map.put(new Student("haha-1",1),"nanjing");//Map映射的特性,键相同,新值覆盖旧值
  68.                 map.put(new Student("haha-3",3),"tianjing");
  69.                
  70.                
  71.                 Set<Student> s = map.keySet();//导出所有的key存入一个set集合
  72.                
  73.                 Iterator<Student> it = s.iterator();
  74.                
  75.           while(it.hasNext())
  76.           {
  77.                   Student key = it.next();//逐个迭代当前键
  78.                   String addr = map.get(key);//取出当前键所对应的值
  79.                   System.out.println(key+"......"+addr);//输出
  80.           }
  81.         }
  82. }

  83. //取出方式2:Map.Entry
  84. class MapTestME
  85. {
  86.         public static void main(String[] args)
  87.         {
  88.                 //建立一个映射集合容器
  89.                 HashMap<Student,String> hm = new HashMap<Student,String>();
  90.                
  91.                 //存入映射元素,夫妻
  92.                 hm.put(new Student("hehe-1",21),"yunnan");
  93.                 hm.put(new Student("hehe-1",21),"guizhou");//重复键,覆盖
  94.                 hm.put(new Student("hehe-3",23),"sichuan");
  95.                
  96.                 //通过hm.entrySet(),将这些夫妻的结婚证存入一个容器
  97.                 Set<Map.Entry<Student,String>> sme = hm.entrySet();
  98.                
  99.                 //迭代,类型为结婚证
  100.                 Iterator<Map.Entry<Student,String>> it = sme.iterator();
  101.                
  102.           while(it.hasNext())
  103.                 {
  104.                         Map.Entry<Student,String> me = it.next();//将来结婚证一个一个的拿出来
  105.                         
  106.                         System.out.println(me.getKey());//取出结婚证里的丈夫
  107.                         System.out.println(me.getValue());        //取出结婚证里的妻子
  108.                 }
  109.         }        
  110. }
复制代码
回复 使用道具 举报
在你调用HashMap中put方法时,首先判断刚加入的键与集合中的键的hash值是否相同,相同,则再调用键这个对象的equals方法。以下是HashMap中put方法的源代码
  1. public V put(K key, V value) {
  2.     if (key == null)
  3.         return putForNullKey(value);
  4.     int hash = hash(key.hashCode());
  5.     int i = indexFor(hash, table.length);
  6.     for (Entry<K,V> e = table[i]; e != null; e = e.next) {
  7.         Object k;
  8.         if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {    //判断在这里。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
  9.             V oldValue = e.value;
  10.             e.value = value;
  11.             e.recordAccess(this);
  12.             return oldValue;
  13.         }
  14.     }

  15.     modCount++;
  16.     addEntry(hash, key, value, i);
  17.     return null;
  18. }
复制代码
回复 使用道具 举报
何仕映 发表于 2013-4-19 15:48
如果是利用hashCode方法来判断键值是否相同,那么在下面这个程序中,打印的结果应该只有一个对象啊。
下 ...

hash值相同,则再比较equals方法的,两个都相同,才是一个对象
回复 使用道具 举报
先小涛 发表于 2013-4-19 15:53
hash值相同,则再比较equals方法的,两个都相同,才是一个对象

谢谢你的解答。
回复 使用道具 举报
文森 中级黑马 2015-5-18 22:16:43
8#
讲的很详细
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马