HashSet 循环
//可以为null HashSet<Object> hashSet =new HashSet<Object>(); hashSet.add(1); hashSet.add("wsss"); hashSet.add(null); for (Object s : hashSet) { System.out.println(s); } System.out.println("-----------"); Iterator iterator = hashSet.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } System.out.println("-----------"); Iterator itor =hashSet.iterator(); for (Object o : hashSet) { if(o instanceof Integer){ Integer n =(Integer)o; System.out.println(n); }else if(o instanceof String){ String str=(String)o; System.out.println(str); }else{ System.out.println(o); } }
HashMap循环
//可以为null HashMap<String,String> hashMap = new HashMap<String,String>(); hashMap.put("1","zhangsan"); hashMap.put("4","lisi"); hashMap.put("7","wangwu"); hashMap.put(null,null); Iterator<Map.Entry<String,String>> iterator =hashMap.entrySet().iterator(); while (iterator.hasNext()){ Map.Entry<String,String> o =iterator.next(); System.out.println(o.getKey()+" "+o.getValue()); } System.out.println("-----------"); for (String key : hashMap.keySet()) { System.out.println(key+" "+hashMap.get(key)); } System.out.println("-----------"); for (Map.Entry<String, String> entry : hashMap.entrySet()) { System.out.println(entry.getKey()+" "+entry.getValue()); } System.out.println("-----------"); //遍历所有value for (String v : hashMap.values()) { System.out.println(v); }
Hashtable循环
//不能为null Hashtable<String,String> hashtable=new Hashtable<String,String>(); hashtable.put("1","zhangsan"); hashtable.put("2","lisi"); hashtable.put("3","wangwu"); for (String key:hashtable.keySet()){ System.out.println(key +" "+hashtable.get(key)); } System.out.println("-----------"); Iterator<Map.Entry<String,String>> iterator = hashtable.entrySet().iterator(); while (iterator.hasNext()){ Map.Entry<String,String> itr =iterator.next(); System.out.println(itr.getKey()+" "+itr.getValue()); } System.out.println("-----------"); for (Map.Entry<String, String> entry : hashtable.entrySet()) { System.out.println(entry.getKey()+" "+entry.getValue()); }
TreeSet 循环
//不能为null TreeSet<String> treeSet =new TreeSet<String>(); treeSet.add("zhangsan"); treeSet.add("ain"); treeSet.add("wangwu"); Iterator iter = treeSet.iterator(); while (iter.hasNext()){ System.out.println(iter.next()); }
区别
1、HashSet实现的是Set接口,HashMap实现的是map接口
2、HashSet存储的是key,,其实更准确的说是存储一个(key,o),o是HashSet里的一个Object型的成员变量;而HashMap存储的是(key-value);Hashtable窜出的是(key-value);
3、Hashtable中,key和value都不允许出现null值,HashSet、HashMap都可以为null值
4、Hashtable中的方法是同步的,而HashMap、HashSet中的方法在缺省情况下是非同步的。
6、添加元素的时候HashMap、Hashtable使用的是put(key,value),HashSet使用的是add(key);
-------------------
TreeSet是一个有序的集合,不允许放入null值,HashSet中的数据是无序的,
TreeSet采用的数据结构是红黑树,HashSet底层用的是哈希表
----------------
TreeMap 是一个有序的key-value集合,它是通过红黑树实现的。
TreeMap 继承于AbstractMap,所以它是一个Map,即一个key-value集合。
TreeMap 实现了NavigableMap接口,意味着它支持一系列的导航方法。比如返回有序的key集合。
TreeMap 实现了Cloneable接口,意味着它能被克隆。
TreeMap 实现了java.io.Serializable接口,意味着它支持序列化。
TreeMap基于红黑树(Red-Black tree)实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。
TreeMap的基本操作 containsKey、get、put 和 remove 的时间复杂度是 log(n) 。
另外,TreeMap是非同步的。 它的iterator 方法返回的迭代器是fail-fastl的。
TreeSet和TreeMap的关系
与HashSet完全类似,TreeSet里面绝大部分方法都市直接调用TreeMap方法来实现的。
相同点:
- TreeMap和TreeSet都是非同步集合,因此他们不能在多线程之间共享,不过可以使用方法Collections.synchroinzedMap()来实现同步
- 运行速度都要比Hash集合慢,他们内部对元素的操作时间复杂度为O(logN),而HashMap/HashSet则为O(1)。
- TreeMap和TreeSet都是有序的集合,也就是说他们存储的值都是拍好序的。
不同点:
- 最主要的区别就是TreeSet和TreeMap分别实现Set和Map接口
- TreeSet只存储一个对象,而TreeMap存储两个对象Key和Value(仅仅key对象有序)
- TreeSet中不能有重复对象,而TreeMap中可以存在
- TreeMap的底层采用红黑树的实现,完成数据有序的插入,排序。
什么是HashMap?
HashMap是一个用于存储Key-Value键值对的集合,每一个键值对也叫做Entry。这些个键值对(Entry)分散存储在一个数组当中,这个数组就是HashMap的主干。
HashMap数组每一个元素的初始值都是Null。
HashMap是非synchronized;HashMap很快
HashMap是在bucket中储存键对象和值对象,作为Map.Entry
HashMap的初始长度是16,并且每次自动扩展或手动初始化时,长度必须是2的幂。
java7:数组+链表
java8:数组+链表+红黑树
java8对hashMap做了什么优化?
ava7中 hashMap每个桶中放置的是链表,这样当hash碰撞严重时,会导致个别位置链表长度过长,从而影响性能。
java8中,HashMap 每个桶中当链表长度超过8之后,会将链表转换成红黑树,从而提升增删改查的速度。
HashMap安排的初始长度,为什么?
初始长度是 16,每次扩展或者是手动初始化,长度必须是 2的幂。
因为: index = HashCode(Key) & (length - 1), 如果 length是 2的 幂的话,则 length - 1就是 全是 1的二进制数,比如 16 - 1 = 1111,这样相当于是 坐落在长度为 length的hashMap上的位置只和 HashCode的后四位有关,这只要给出的HashCode算法本身分布均匀,算出的index就是分布均匀的。
因为HashMap的key是int类型,所以最大值是2^31次方,但是查看源码,当到达 2^30次方,即 MAXIMUM_CAPACITY,之后,便不再进行扩容。
你知道HashMap的get()方法的工作原理吗?
HashMap是基于hashing的原理,我们使用put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。当我们给put()方法传递键和值时,我们先对键调用hashCode()方法,返回的hashCode用于找到bucket位置来储存Entry对象.
使用Get方法根据Key来查找Value的时候,HashMap会使用键对象的hashcode找到bucket位置
当两个对象的hashcode相同会发生什么?
因为hashcode相同,所以它们的bucket位置相同,‘碰撞’会发生。因为HashMap使用LinkedList存储对象,这个Entry(包含有键值对的Map.Entry对象)会存储在LinkedList中
如果两个键的hashcode相同,你如何获取值对象?
当我们调用get()方法,HashMap会使用键对象的hashcode找到bucket位置,找到bucket位置之后,会调用keys.equals()方法去找到LinkedList中正确的节点,最终找到要找的值对象
如果HashMap的大小超过了负载因子(load factor)定义的容量,怎么办?
默认的负载因子大小为0.75,也就是说,当一个map填满了75%的bucket时候,和其它集合类一样,将会创建原来HashMap大小的两倍的bucket数组,来重新调整map的大小,并将原来的对象放入新的bucket数组中。这个过程叫作(再散列)rehashing,因为它调用hash方法找到新的bucket位置。
可以使用自定义的对象作为键吗?
可以使用任何对象作为键,只要它遵守了equals()和hashCode()方法的定义规则,并且当对象插入到Map中之后将不会再改变了。如果这个自定义对象时不可变的,那么它已经满足了作为键的条件,因为当它创建之后就已经不能改变了。
可以使用CocurrentHashMap来代替HashTable吗?
HashTable是synchronized的,但是ConcurrentHashMap同步性能更好,因为它仅仅根据同步级别对map的一部分进行上锁。ConcurrentHashMap当然可以代替HashTable,但是HashTable提供更强的线程安全性。
为什么String, Interger这样的wrapper类适合作为键?
因为String是不可变的,也是final的,而且已经重写了equals()和hashCode()方法了。其他的wrapper类也有这个特点。不可变性是必要的,
因为为了要计算hashCode(),就要防止键值改变,如果键值在放入时和获取时返回不同的hashcode的话,那么就不能从HashMap中找到你想要的对象。不可变性还有其他的优点如线程安全。如果你可以仅仅通过将某个field声明成final就能保证hashCode是不变的,那么请这么做吧。因为获取对象的时候要用到equals()和hashCode()方法,那么键对象正确的重写这两个方法是非常重要的。如果两个不相等的对象返回不同的hashcode的话,那么碰撞的几率就会小些,这样就能提高HashMap的性能。