java中的几种泛型类——HashSet、HashMap、TreeSet、TreeMap,遍历map,排序,HashTable比较

来源:互联网 发布:mac pd好还是vm好 编辑:程序博客网 时间:2024/05/16 09:29

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)方法将键-值对存储在散列映射中,同时返回键所对应的值。
   遍历散列映射的方法有如下四种:
public static void main(String[] args) {Map<String, String> map = new HashMap<String, String>();map.put("1", "value1");map.put("2", "value2");map.put("3", "value3");// 第一种:普遍使用,二次取值System.out.println("通过Map.keySet遍历key和value:");for (String key : map.keySet()) {System.out.println("key= " + key + " and value= " + map.get(key));}// 第二种System.out.println("通过Map.entrySet使用iterator遍历key和value:");Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();while (it.hasNext()) {Map.Entry<String, String> entry = it.next();System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());}// 第三种:推荐,尤其是容量大时System.out.println("通过Map.entrySet遍历key和value");for (Map.Entry<String, String> entry : map.entrySet()) {System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());}// 第四种System.out.println("通过Map.values()遍历所有的value,但不能遍历key");for (String v : map.values()) {System.out.println("value= " + v);}}
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接口规定的大小顺序对树映射中的键-值对进行排序,即可以升序,也可以降序,取决于里面重写的方法。
   下面是一个排序的例子:
package test;import java.util.Collections;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.TreeMap;public class Sort {public static void main(String[] args) {System.out.println("开始:");Person person1 = new Person("马先生", 220181);Person person2 = new Person("李先生", 220193);Person person3 = new Person("王小姐", 220186);Map<Number, Person> map = new HashMap<Number, Person>();map.put(person1.getIdCard(), person1);map.put(person2.getIdCard(), person2);map.put(person3.getIdCard(), person3);System.out.println("由HashMap类实现的Map集合,无序:");for (Iterator<Number> it = map.keySet().iterator(); it.hasNext();) {// 遍例集合Person person = map.get(it.next());System.out.println(person.getIdCard() + " " + person.getName());}System.out.println("由TreeMap类实现的Map集合,键对象升序:");TreeMap<Number, Person> treeMap = new TreeMap<Number, Person>();treeMap.putAll(map);for (Iterator<Number> it = treeMap.keySet().iterator(); it.hasNext();) {// 遍例集合Person person = treeMap.get(it.next());System.out.println(person.getIdCard() + " " + person.getName());}System.out.println("由TreeMap类实现的Map集合,键对象降序:");TreeMap<Number, Person> treeMap2 = new TreeMap<Number, Person>(Collections.reverseOrder());// 初始化为反转排序treeMap2.putAll(map);for (Iterator it = treeMap2.keySet().iterator(); it.hasNext();) {// 遍例集合Person person = (Person) treeMap2.get(it.next());System.out.println(person.getIdCard() + " " + person.getName());}System.out.println("结束!");}}class Person {private String name;private long idCard;public Person(String name, long idCard) {this.name = name;this.idCard = idCard;}public long getIdCard() {return idCard;}public void setIdCard(long idCard) {this.idCard = idCard;}public String getName() {return name;}public void setName(String name) {this.name = name;}}

     输出结果为:
开始:由HashMap类实现的Map集合,无序:220186 王小姐220181 马先生220193 李先生由TreeMap类实现的Map集合,键对象升序:220181 马先生220186 王小姐220193 李先生由TreeMap类实现的Map集合,键对象降序:220193 李先生220186 王小姐220181 马先生结束!

TreeMap也可以用一个简单的方法使它按键key降序排列:
TreeMap<Double, double[]> sortMap = new TreeMap<Double, double[]>(<span style="color:#ff0000;">Collections.reverseOrder()</span>);// 初始化为翻转排序

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

map中按值排序则需要重写Comparator方法,如下的例子:
 List<Map.Entry<Integer, Double>> entrySet = new ArrayList<Map.Entry<Integer, Double>>(map.entrySet()); System.out.println("排序前的特征值: " + entrySet); Collections.sort(entrySet,new <span style="color:#ff0000;">Comparator</span><Map.Entry<Integer, Double>>() { public int compare(Entry<Integer, Double> o1, Entry<Integer, Double> o2) { return o2.getValue().compareTo(o1.getValue());//<span style="color:#ff0000;">此处对象o1和对象o2的先后顺序可决定是按升序还是按降序排序</span> } });

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读不加锁 

——————————————————————————————————————————————————————
写博经验尚浅,请各位多多指教。


0 0
原创粉丝点击