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读不加锁
——————————————————————————————————————————————————————写博经验尚浅,请各位多多指教。