HashSet

HashSet<E>泛型类在数据组织上类似于数学上的集合,可以进行“交”、“并”、“差”等运算。 HashSet<E>泛型类创建的对象称为集合,如:     HashSet<E> set =  HashSet<String>();     那么set就是一个可以存储string类型数据的集合,set可以调用add(String s)方法将string类型的数据添加到集合中。添加到集合中的数据称为集合的元素。集合不允许有相同的元素。也就是说,如果b已经是集合中的元素,那么执行add(b)的操作是无效的。集合对象的初始容量是16字节,装载因子是0.75。也就是说,如果集合添加的元素超过总容量的75%是,集合的容量将增加1倍。 相关运算: 并运算: boolean addAll(HashSet); 交运算:boolean retainAll(HashSet); 差运算:boolean remainAll(HashSet); 参数指定的集合必须与当前集合是同种类型的集合,否则上述方法返回的类型是false。 HashSet<E>泛型类实现了泛型接口Set<E>,而Set<E>接口是Collection<E>接口的子接口。HashSet<E>类中的绝大部分方法都是接口方法的实现。编程时,可以使用接口回调技术,即把HashSet<E>对象的引用赋值给Collection<E>接口变量或Set<E>接口变量,那么接口就可以调用类实现的接口方法。


HashMap

HashMap<K,V>对象成为散列映射对象。散列映射用于存储键-值数据对,允许把任何数量的键-值数据存储在一起。键不可以可重复。如果出现两个数据项的键相同,那么先前散列映射中的键-值对将被替换。散列映射在它需要更多存储容量是会自动增大容量。例如,如果散列映射的装载因子是75%时,它就自动把容量增加到原始容量的2倍。对于数组和链表这两种数据结构,如果要查找它们存储的某个特定的元素却不知道它们的位置,就需要从头开始访问元素知道找到匹配的为止;如果数据结构中包含很多元素,就会浪费时间。这时最好使用散列映射来存储要找的数据,以便检索时可以减少检索的开销。 HashMap<K,V>泛型类创建的对象称为散列映射,如:

     HashMap<K,V> hash = HashMap<String,Student>();      那么,hash就可以存储键-值对数据,其中的键必须是一个String对象,键对应的值必须是Student对象。hash可以调用 public V put(K key, V value)方法将键-值对存储在散列映射中,同时返回键所对应的值。    遍历散列映射的方法有如下四种: ​[html]​ ​​view plain​​ copy


  1. public static void main(String[] args) {  
  2.     Map<String, String> map = new HashMap<String, String>();  
  3.     map.put("1", "value1");  
  4.     map.put("2", "value2");  
  5.     map.put("3", "value3");  

  6.     // 第一种:普遍使用,二次取值  
  7.     System.out.println("通过Map.keySet遍历key和value:");  
  8.     for (String key : map.keySet()) {  
  9.         System.out.println("key= " + key + " and value= " + map.get(key));  
  10.     }  

  11.     // 第二种  
  12.     System.out.println("通过Map.entrySet使用iterator遍历key和value:");  
  13.     Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();  
  14.     while (it.hasNext()) {  
  15.         Map.Entry<String, String> entry = it.next();  
  16.         System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());  
  17.     }  

  18.     // 第三种:推荐,尤其是容量大时  
  19.     System.out.println("通过Map.entrySet遍历key和value");  
  20.     for (Map.Entry<String, String> entry : map.entrySet()) {  
  21.         System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());  
  22.     }  

  23.     // 第四种  
  24.     System.out.println("通过Map.values()遍历所有的value,但不能遍历key");  
  25.     for (String v : map.values()) {  
  26.         System.out.println("value= " + v);  
  27.     }  
  28. }  

HashMap<E>泛型类是实现泛型接口Map<E>。

TreeSet

TreeSet<E>类是实现Set接口的类。

TreeSet<E>泛型类创建的对象称为树集,如:

     TreeSet<Student> tree = TreeSet<Student>();      那么tree就是一个可以存储Student对象的集合,tree可以调用add(Student s)方法将Student对象添加到树集中。树集采用树结构存储数据,树集节点的排列和链表不同,不按添加的先后顺序顺序排列。树集采用add()方法增加节点,节点会按其存放的数据的“大小”顺序一层一层地依次排序,同一层的节点按“大小”顺序递增排列,下一层的比上一层的小。树集是一个有序集合。

TreeMap

TreeMap类实现了Map接口,TreeSet类提供了按排序顺序存储键-值对的有效手段。 ​TreeMap保证它的元素按key升序排列。​ 构造函数有2种:    TreeMap<K,V>()按照关键字key的大小顺序来对键-值对进行升序排序,key的顺序是按其字符串表示的字典顺序。    TreeMap<K,V>(Comparator<K> comp)关键字key的大小顺序按照Comparator接口规定的大小顺序对树映射中的键-值对进行排序,即可以升序,也可以降序,取决于里面重写的方法。    下面是一个排序的例子: ​[html]​ ​​view plain​​ ​​copy​


  1. package test;  

  2. import java.util.Collections;  
  3. import java.util.HashMap;  
  4. import java.util.Iterator;  
  5. import java.util.Map;  
  6. import java.util.TreeMap;  

  7. public class Sort {  

  8.     public static void main(String[] args) {  
  9.         System.out.println("开始:");  
  10.         Person person1 = new Person("马先生", 220181);  
  11.         Person person2 = new Person("李先生", 220193);  
  12.         Person person3 = new Person("王小姐", 220186);  
  13.         Map<Number, Person> map = new HashMap<Number, Person>();  
  14.         map.put(person1.getIdCard(), person1);  
  15.         map.put(person2.getIdCard(), person2);  
  16.         map.put(person3.getIdCard(), person3);  
  17.         System.out.println("由HashMap类实现的Map集合,无序:");  
  18.         for (Iterator<Number> it = map.keySet().iterator(); it.hasNext();) {// 遍例集合  
  19.             Person person = map.get(it.next());  
  20.             System.out.println(person.getIdCard() + " " + person.getName());  
  21.         }  
  22.         System.out.println("由TreeMap类实现的Map集合,键对象升序:");  
  23.         TreeMap<Number, Person> treeMap = new TreeMap<Number, Person>();  
  24.         treeMap.putAll(map);  
  25.         for (Iterator<Number> it = treeMap.keySet().iterator(); it.hasNext();) {// 遍例集合  
  26.             Person person = treeMap.get(it.next());  
  27.             System.out.println(person.getIdCard() + " " + person.getName());  
  28.         }  
  29.         System.out.println("由TreeMap类实现的Map集合,键对象降序:");  
  30.         TreeMap<Number, Person> treeMap2 = new TreeMap<Number, Person>(  
  31.                 Collections.reverseOrder());// 初始化为反转排序  
  32.         treeMap2.putAll(map);  
  33.         for (Iterator it = treeMap2.keySet().iterator(); it.hasNext();) {// 遍例集合  
  34.             Person person = (Person) treeMap2.get(it.next());  
  35.             System.out.println(person.getIdCard() + " " + person.getName());  
  36.         }  
  37.         System.out.println("结束!");  
  38.     }  
  39. }  

  40. class Person {  
  41.     private String name;  
  42.     private long idCard;  

  43.     public Person(String name, long idCard) {  
  44.         this.name = name;  
  45.         this.idCard = idCard;  
  46.     }  

  47.     public long getIdCard() {  
  48.         return idCard;  
  49.     }  

  50.     public void setIdCard(long idCard) {  
  51.         this.idCard = idCard;  
  52.     }  

  53.     public String getName() {  
  54.         return name;  
  55.     }  

  56.     public void setName(String name) {  
  57.         this.name = name;  
  58.     }  
  59. }  


     输出结果为: ​[html]​ ​​view plain​​ ​​copy​


  1. 开始:  
  2. 由HashMap类实现的Map集合,无序:  
  3. 220186 王小姐  
  4. 220181 马先生  
  5. 220193 李先生  
  6. 由TreeMap类实现的Map集合,键对象升序:  
  7. 220181 马先生  
  8. 220186 王小姐  
  9. 220193 李先生  
  10. 由TreeMap类实现的Map集合,键对象降序:  
  11. 220193 李先生  
  12. 220186 王小姐  
  13. 220181 马先生  
  14. 结束!  


TreeMap也可以用一个简单的方法使它按键key降序排列: ​[html]​ ​​view plain​​ ​​copy​

  1. TreeMap<Double, double[]> sortMap = new TreeMap<Double, double[]>(<span style="color:#ff0000;">Collections.reverseOrder()</span>);// 初始化为翻转排序  


所以,如果map需要​按键排序​,把键-值对放在TreeMap即可。

map中​按值排序​则需要重写Comparator方法,如下的例子: ​[html]​ ​​view plain​​ ​​copy​


  1. List<Map.Entry<Integer, Double>> entrySet = new  
  2.      ArrayList<Map.Entry<Integer, Double>>(map.entrySet());  
  3.      System.out.println("排序前的特征值: " + entrySet);  
  4.      Collections.sort(entrySet,new <span style="color:#ff0000;">Comparator</span><Map.Entry<Integer, Double>>() {  
  5.      public int compare(Entry<Integer, Double> o1,  
  6.      Entry<Integer, Double> o2) {  
  7.      return o2.getValue().compareTo(o1.getValue());//<span style="color:#ff0000;">此处对象o1和对象o2的先后顺序可决定是按升序还是按降序排序</span>  
  8.      }  
  9.      });  


Map常用操作

         1) 添加操作:
        V put(K key, V value):如果key已存在,在关联后,返回替换前该key对应的value值,如果不存在,则返回null;
        void putAll(Map t):将来自特定映像的所有元素添加给该映射。
    2) 删除操作:
        V remove(Object key):从此映射中移除指定键的映射关系(如果存在),不存在则返回null;
        void clear() :从此映射中移除所有映射关系. 
    3) 查询操作:
        V get(key): 获得与关键字key相关的值,并且返回与关键字key相关的对象,如果没有该关键字,则返回null;判断key是否存在,可以通过返回值是否等于null
        boolean containsKey(key): 判断映像中是否存在关键字key;
        boolean containsValue(Object value): 判断映像中是否存在值value;
        int size(): 返回当前映像中映射的数量;
        boolean isEmpty(): 判断映像中是否有任何映射.
        Collection values():返回映像中所有value值的集,由于值多个,用Collection集合,对其操作可以使用Collection基本方法.


HashMap和HashTable的区别:

      1) HashTable:底层是​哈希表​数据结构;hash值直接使用对象的hashCode;不可以存入null键和null值;hash数组默认大小是11,增加的方式是 old*2+1;线程同步,在多线程并发的环境下,可以直接使用Hashtable;JDK1.0效率低;    2) HashMap:继承自Dictionary类,底层是​哈希表​数据结构;重新计算hash值;可以存入null键和null值;hash数组的默认大小是16,而且一定是2的指数;线程不同步,在多线程并发的环境下,要自己增加同步处理;JDK1.2效率高。     一般情况下,HashMap能够比Hashtable工作的更好、更快,主要得益于它的散列算法,以及没有同步。应用程序一般在更高的层面上实 现了保护机制,而不是依赖于这些底层数据结构的同步,因此,HashMap能够在大多应用中满足需要。推荐使用HashMap,如果需要同步,可以使用同步工具类将其转换成支持同步的HashMap。


LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。

有并发访问的时候用ConcurrentHashMap,效率比用锁的HashMap好 功能上可以,但是毕竟ConcurrentHashMap这种数据结构要复杂些,如果能保证只在单一线程下读写,不会发生并发的读写,那么就可以试用HashMap。ConcurrentHashMap读不加锁