hashmap,hashset

来源:互联网 发布:什么精华液比较好知乎 编辑:程序博客网 时间:2024/05/17 06:21
1、hashmap的数据结构 
要知道hashmap是什么,首先要搞清楚它的数据结构,在java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,hashmap也不例外。Hashmap实际上是一个数组和链表的结合体(在数据结构中,一般称之为“链表散列“),请看下图(横排表示数组,纵排表示数组元素【实际上是一个链表】)。
 

 

从图中我们可以看到一个hashmap就是一个数组结构,当新建一个hashmap的时候,就会初始化一个数组。我们来看看java代码: 

Java代码  收藏代码
  1. /** 
  2.      * The table, resized as necessary. Length MUST Always be a power of two. 
  3.      *  FIXME 这里需要注意这句话,至于原因后面会讲到 
  4.      */  
  5.     transient Entry[] table;  

Java代码  收藏代码
  1. static class Entry<K,V> implements Map.Entry<K,V> {  
  2.         final K key;  
  3.         V value;  
  4.         final int hash;  
  5.         Entry<K,V> next;  
  6. ..........  
  7. }  


        上面的Entry就是数组中的元素,它持有一个指向下一个元素的引用,这就构成了链表。 

         当我们往hashmap中put元素的时候,先根据key的hash值得到这个元素在数组中的位置(即下标,一般情况是通过hash(key)%len获得),然后就可以把这个元素放到对应的位置中了。如果这个元素所在的位子上已经存放有其他元素了(hash冲突),那么在同一个位子上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。从hashmap中get元素时,首先计算key的hashcode,找到数组中对应位置的某一元素,然后通过key的equals方法在对应位置的链表中找到需要的元素。从这里我们可以想象得到,如果每个位置上的链表只有一个元素,那么hashmap的get效率将是最高的,但是理想总是美好的,现实总是有困难需要我们去克服,哈哈~ 


从hashmap中取元素时,get方法首先计算key的hashcode,找到数组中对应位置的某一元素,然后通过key的equals方法在对应位置的链表中找到需要的元素。所以,hashcode与equals方法对于找到对应元素是两个关键方法。 

Hashmap的key可以是任何类型的对象,例如User这种对象,为了保证两个具有相同属性的user的hashcode相同,我们就需要改写hashcode方法,比方把hashcode值的计算与User对象的id关联起来,那么只要user对象拥有相同id,那么他们的hashcode也能保持一致了,这样就可以找到在hashmap数组中的位置了。如果这个位置上有多个元素,还需要用key的equals方法在对应位置的链表中找到需要的元素,所以只改写了hashcode方法是不够的,equals方法也是需要改写滴


使用HashMap,如果key是自定义的类,就必须重写hashcode()和equals()。

默认的equals()方法只有两个引用都是引用同一个对象的时候才是true(跟“==“一样)

  1.         Cat c1 = new Cat(123);   
  2.         Cat c2 = new Cat(126);   
  3.         System.out.println(c1 == c2); //false   
  4.         System.out.println(c1.equals(c2)); //false   
  5.         String s1 = new String("hello");    
  6.         String s2 = new String("hello");   
  7.         String m1 = "hello";   
  8.         String m2 = "hello";   
  9.         System.out.println(s1 == s2); //false   
  10.         System.out.println(m1 == m2); //true   
  11.         System.out.println(s1.equals(s2));  //true ,如果没有重写equals方法,也是false

  1. //实体类   
  2. class Cat {   
  3.     int color;   
  4.     int height, weight;   
  5.        
  6.     public Cat(int color, int height, int weight) {   
  7.         this.color = color;   
  8.         this.height = height;   
  9.         this.weight = weight;   
  10.     }   
  11.     //重写equals方法   
  12.     public boolean equals(Object obj) {   
  13.         if(obj == nullreturn false;   
  14.         else {   
  15.             if(obj instanceof Cat) {   
  16.                 Cat c = (Cat)obj;   
  17.                 if(c.color == this.color && c.height    
  18.                 == this.height && c.weight == this.weight) {   
  19.                     return true;   
  20.                 }   
  21.             }   
  22.         }   
  23.         return false;   
  24.     }   
  25. }  


hashset:

1.HashSet概述:

  HashSet实现Set接口,由哈希表(实际上是一个HashMap实例)支持。它不保证set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用null元素。HashSet中不允许有重复元素,这是因为HashSet是基于HashMap实现的,HashSet中的元素都存放在HashMap的key上面,而value中的值都是统一的一个private static final Object PRESENT = new Object();。HashSet跟HashMap一样,都是一个存放链表的数组。

  HashSet中add方法调用的是底层HashMap中的put()方法,而如果是在HashMap中调用put,首先会判断key是否存在,如果key存在则修改value值,如果key不存在这插入这个key-value。而在set中,因为value值没有用,也就不存在修改value值的说法,因此往HashSet中添加元素,首先判断元素(也就是key)是否存在,如果不存在这插入,如果存在着不插入,这样HashSet中就不存在重复值。

2.HashSet的实现:

  对于HashSet而言,它是基于HashMap实现的,HashSet底层使用HashMap来保存所有元素,更确切的说,HashSet中的元素,只是存放在了底层HashMap的key上, 而value使用一个static final的Object对象标识。因此HashSet 的实现比较简单,相关HashSet的操作,基本上都是直接调用底层HashMap的相关方法来完成

第一:HashSet的构造和增加元素

集合中存放的是对象的引用。集合中元素的存储空间是自动开辟的,不像数组需要预先开辟内存。

HashSet hashSet = new HashSet();
  hashSet.add(new Integer(1)); //向集合中添加一个整数
  hashSet.add("a"); //向集合中添加一个字符串
  int x[] = {1,2,3,4,5};
  hashSet.add(x); //向集合中添加一个数组
  Person p = new Person("张三", 23, "男", "研究生");
  hashSet.add(p); //向集合中添加一个自定义类的对象

第二:HashSet的遍历

所谓遍历就是按照某种顺序,对于集合中的每个元素访问一次并且仅一次,不重复也不遗漏。

Iterator it = hashSet.iterator();
  while(it.hasNext()){
   Object obj = it.next();
   if(obj instanceof Integer){
    System.out.println("integer:"+obj);
   }
   if(obj instanceof String){
    System.out.println("String:"+obj);
   }
   if(obj instanceof int[]){
    System.out.println("integer:"+x[4]);
   }
   if(obj instanceof Person){
    System.out.println("Person:"+p.getName()+p.getAge()+p.getSex()+p.getEducation());
    
   }
  }

输出结果是:

integer:1
integer:5
String:a
Person:张三23男研究生

注意:(1)因为集合是无序的,所以输出结果也是无序的。

         (2)判断对象是否是数组 obj.getClass().isArray()。

         (3)判断对象是否是所属地类obj.getClass().getName()。

 第三:删除HashSet中的元素

删除一个元素:hashSet.remove(Object);

删除所有元素:hashSet.clear();

第四:判断是否包含某个元素

if(hashSet.contains(new String("a"))){
   System.out.println("String");
  }





原创粉丝点击