今天迭代hashmap时,hashmap并不能按照put的顺序,迭代输出值。用下述方法可以:
HashMap<String,String> hashmap = new LinkedHashMap<String,String>();
方法一:
把HashSet保存在ArrayList里,再用Collections.sort()方法比較
- private void doSort(){
- final HashSet<Integer> va = new HashSet<Integer>();
- va.add(2007111315);
- va.add(2007111314);
- va.add(2007111318);
- va.add(2007111313);
- final List<Integer> list = new ArrayList<Integer>();
- for(final Integer value : va){
- list.add(value);
- }
- Collections.sort(list);
- System.out.println(list);
- }
-
方二法:
把这个HashSet做为构造参数放到TreeSet中就可以排序了
-
- final TreeSet ts = new TreeSet(va);
- ts.comparator();
- System.out.println(ts);
1. HashSet是通过HashMap实现的,TreeSet是通过TreeMap实现的,只不过Set用的只是Map的key
2. Map的key和Set都有一个共同的特性就是集合的唯一性.TreeMap更是多了一个排序的功能.
3. hashCode和equal()是HashMap用的, 因为无需排序所以只需要关注定位和唯一性即可.
a. hashCode是用来计算hash值的,hash值是用来确定hash表索引的.
b. hash表中的一个索引处存放的是一张链表, 所以还要通过equal方法循环比较链上的每一个对象 才可以真正定位到键值对应的Entry.
c. put时,如果hash表中没定位到,就在链表前加一个Entry,如果定位到了,则更换Entry中的value,并返回旧value
4. 由于TreeMap需要排序,所以需要一个Comparator为键值进行大小比较.当然也是用Comparator定位的.
a. Comparator可以在创建TreeMap时指定
b. 如果创建时没有确定,那么就会使用key.com
是的, 这是一个太多太多人遇到过, 讨论过, 解释过的问题.
为了加深自己的记忆, 还是决定写一篇来记录下他.
首先想说的是:
Vector是在Collections API之前就已经产生了的, 而ArrayList是在JDK1.2的时候才作为Collection framework的一部分引入的. 它们都是在内部用一个Obejct[]来存储元素的.
ok, 现在来说他们的差别:
1. 线程安全
Vector是同步的, 而ArrayList不是.
因为Vector是同步的, 所以它是线程安全的.
同样, 因为Vecotr是同步的, 所以他需要额外的开销来维持同步锁, 所以它要比ArrayList要慢.(理论上来说)
当然, 如果你对ArrayList有偏好, 你也可以用Collection.synchronizedList(List)来得到一个线程安全的List.
2. 容量增长
Vector允许用户设置capacityIncrement这样在每次需要扩充数组的size的时候, Vector会尝试按照预先设置的capacityIncrement作为增量来设置, 而ArrayList则会把数组的大小扩大一倍.
比如现在同样一个长度为10的Vector和ArrayList, 我们把Vector的capacityIncrement设为1
那么我们在插入第11个对象的时候, Vector会将长度变成11, 然后分配空间, 然后将对象添加进去, 而ArrayList则会分配20个对象的空间, 然后将对象添加进去.
如果capacityIncrement设为0或者负值, Vector就会做和ArrayList一样, 每次都将数组大小扩大一倍.
3. 性能比较
刚刚在上面已经说过了, 由于Vector是同步的, 而ArrayList不是, 所以Vector的性能要比ArrayList要稍第一点, 用性能换安全嘛.
不过, 据Jack Shirazi在OnJava上的一篇文章来看, 似乎这并不是什么问题, 他认为对于现在的JVM来说, 这两个类在同步这个问题上的性能差异, 甚至还不如每次跑测试的时候环境变化引起的差异大.
Consequently Vector is thread-safe, and ArrayList isn't. This makes ArrayList faster than Vector. For some of the latest JVMs the difference in speed between the two classes is negligible: strictly speaking, for these JVMs the difference in speed between the two classes is less than the variation in times obtained from tests comparing the performance of these classes. ---- The Performance of Java's Lists
这样看来, 性能上的差别应该不大.
So, as a conclusion.
结论和网上大多数人得到的结论一样:
在一般情况下, 还是鼓励用ArrayList的, 如果你有同步控制的需要, 那就用Vector吧, 也懒得用Collection.synchronizedList(List)再去转一次了, 除非非这样不可.. 不然还是顺应潮流, 毕竟, 代码是写给人看的. 在无伤大雅的情况下, 按照common的法则来写, 无疑会让看代码的人更快理解. :)
1、 继承和实现区别
Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现。
2、 线程安全不同
HashTable的方法是同步的,HashMap是未同步,所以在多线程场合要手动同步HashMap。
3、 对null的处理不同
HashTable不允许null值(key和value都不可以),HashMap允许null值(key和value都可以)。即HashTable 不允许null值其实在编译期不会有任何的不一样,会照样执行,只是在运行期的时候Hashtable中设置的话回出现空指针异常。HashMap允许 null值是指可以有一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示 HashMap中没有该键,也可以表示该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键,而应该用containsKey()方法来判断。
4、 方法不同
HashTable有一个contains(Object value),功能和containsValue(Object value)功能一样。
5、HashTable使用Enumeration,HashMap使用Iterator。
6、HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。
7、哈希值的使用不同,HashTable直接使用对象的hashCode,代码是这样的:
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
而HashMap重新计算hash值,而且用与代替求模:
int hash = hash(k);
int i = indexFor(hash, table.length);
static int hash(Object x) {
int h = x.hashCode();
h += ~(h << 9);
h ^= (h >>> 14);
h += (h << 4);
h ^= (h >>> 10);
return h;
}
static int indexFor(int h, int length) {
return h & (length-1);
}
区别 |
Hashtable |
Hashmap |
继承、实现 |
Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable,Serializable |
HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable,Serializable
|
线程同步 |
已经同步过的可以安全使用 |
未同步的,可以使用Colletcions进行同步Map Collections.synchronizedMap(Map m) |
对null的处理
|
Hashtable table = new Hashtable(); table.put(null, "Null"); table.put("Null", null); table.contains(null); table.containsKey(null); table.containsValue(null); 后面的5句话在编译的时候不会有异常,可在运行的时候会报空指针异常具体原因可以查看源代码 public synchronized V put(K key, V value) { // Make sure the value is not null if (value == null) { throw new NullPointerException(); } |
HashMap map = new HashMap(); map.put(null, "Null"); map.put("Null", null); map.containsKey(null); map.containsValue(null); 以上这5条语句无论在编译期,还是在运行期都是没有错误的. 在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示 HashMap中没有该键,也可以表示该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键,而应该用containsKey()方法来判断。 |
增长率 |
protected void rehash() { int oldCapacity = table.length; Entry[] oldMap = table; int newCapacity = oldCapacity * 2 + 1; Entry[] newMap = new Entry[newCapacity]; modCount++; threshold = (int)(newCapacity * loadFactor); table = newMap; for (int i = oldCapacity ; i-- > 0 ;) { for (Entry<K,V> old = oldMap[i] ; old != null ; ) { Entry<K,V> e = old; old = old.next; int index = (e.hash & 0x7FFFFFFF) % newCapacity; e.next = newMap[index]; newMap[index] = e; } } }
|
void addEntry(int hash, K key, V value, int bucketIndex) { Entry<K,V> e = table[bucketIndex]; table[bucketIndex] = new Entry<K,V>(hash, key, value, e); if (size++ >= threshold) resize(2 * table.length); }
|
哈希值的使用 |
HashTable直接使用对象的hashCode,代码是这样的: public synchronized booleancontainsKey(Object key) { Entry tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return true; } } return false; } |
HashMap重新计算hash值,而且用与代替求模 public boolean containsKey(Object key) { Object k = maskNull(key); int hash = hash(k.hashCode()); int i = indexFor(hash, table.length); Entry e = table[i]; while (e != null) { if (e.hash == hash && eq(k, e.key)) return true; e = e.next; } return false; }
|
相关推荐
`HashMap`的关键特性是其非线程安全性和元素的无序性。为了确保`HashMap`的性能,元素的`hashCode()`和`equals()`方法应该被正确实现,以避免哈希冲突和确保正确的元素相等性判断。 在代码示例中,可以看到`...
因此,HashSet判断元素是否重复的方式与HashMap类似:首先计算元素的哈希值,然后通过equals()方法检查是否存在相同的元素。 **TreeMap** TreeMap是一个有序的键值对存储结构,它根据键的自然顺序或者自定义比较器...
4. HashSet(int capacity, float fillRatio):除了初始容量,这个构造函数还允许用户定义一个填充比率(负载因子),它决定了当HashSet中的元素数量达到容量与填充比率的乘积时,HashSet的容量会进行扩展。...
HashSet是基于哈希表实现的一种无序集合,不允许有重复元素。在C++中,可以使用`std::unordered_set`来实现HashSet。它提供了快速的插入、删除和查找操作,平均时间复杂度为O(1)。HashSet通过哈希函数将元素映射到...
在Java中,Collection接口的子接口包括Set和List,分别代表无序集合和有序集合。Map接口用于保存具有key-value映射关系的数据,常见的Map实现包括HashMap、TreeMap、HashTable和LinkedHashMap等。Queue是Java提供的...
与`HashMap`类似,它也是基于哈希表实现的,但不允许使用`null`键或值。 - **特点**: - **线程安全**:由于它内部使用了`synchronized`关键字,所以可以直接在多线程环境中使用。 - **不支持null**:既不允许`...
3. HashSet vs HashMap:HashSet是基于HashMap实现的,存储元素,没有键值对概念;HashMap存储键值对,两者均不保证元素顺序。 4. HashMap vs HashTable:HashMap是非线程安全且允许null键和值,而HashTable是线程...
首先,HashSet 是基于哈希表(HashMap 实例)来存储元素的,因此它提供了快速的插入、删除和查找操作。哈希表依赖于对象的 `hashCode()` 方法来确定元素的存储位置,而 `equals()` 方法用于判断两个对象是否相等。在...
HashSet以其高效性和无序性适合大部分需求,而TreeSet则在需要有序存储和快速查找、排序的场合表现出优势。了解和掌握这两种集合类的源码分析有助于深入理解Java集合框架的底层实现,从而更好地应用在实际开发中。
- HashSet是基于HashMap实现的无序集合,不允许有重复元素。它的底层使用HashMap存储元素,插入和查找速度较快,但不保证元素顺序。 - HashMap是一个键值对的存储结构,查找、插入和删除操作的时间复杂度通常为O(1...
HashSet的实现基于HashMap,其内部元素的顺序由元素的hashCode决定,而不是插入顺序。在HashSet中,每个元素都是HashMap中的一个键(key),对应的值是PRESENT对象。当尝试添加一个元素时,HashSet会使用HashMap的...
HashSet基于HashMap,插入和查找速度快,但无序;TreeSet内部使用红黑树实现,保证元素有序,插入和查找速度较HashSet慢。 二、Map接口 Map接口用于存储键值对,不包含在Collection接口中。HashMap、HashTable和...
- HashMap与HashSet:HashMap存储键值对,HashSet存储元素,两者都基于哈希表,但HashSet是HashMap的一个简化版本。 - HashMap与TreeMap:HashMap无序,而TreeMap基于红黑树,保持键的排序。 8. **...
2. 实现:接口的具体实现包括ArrayList、LinkedList、HashSet、HashMap等。ArrayList是一个动态数组,适合随机访问但插入和删除效率较低;LinkedList是双向链表,适合插入和删除但随机访问效率低;HashSet基于...
本指南将深入探讨HashMap、HashSet、HashTable、LinkedHashMap、LinkedHashSet、ArrayList、LinkedList、ConcurrentHashMap等主要集合类的实现原理,以及它们在实际应用中的选择与比较。 首先,HashMap是最常用的...
Set无序,不允许元素重复,通常使用HashSet或TreeSet。Set的插入和删除操作比List高效,但查找效率相对较低。 3. **线程安全性**: HashMap在多线程环境下不是线程安全的。由于多个线程同时修改HashMap可能导致...
本文将深入探讨Java集合框架的核心概念,包括List、Set、Map等接口,以及ArrayList、LinkedList、HashSet、HashMap等实现类,帮助你理解和解决面试中的相关问题。 1. **List和Set的区别及应用场景** - **List** 是...
HashSet是无序且不包含重复元素的集合,它基于哈希表实现。当我们添加元素到HashSet时,元素的hashCode被用来快速定位元素的位置,从而实现快速的添加、查找和删除操作。但是,HashSet不保留元素的插入顺序。 ...
`HashSet`是基于`HashMap`实现的,它不保证元素的顺序,允许包含null值但不允许有重复元素。`HashSet`的插入、删除和查找操作的时间复杂度通常为O(1),这是因为它们依赖于哈希函数的快速定位能力。当我们向`HashSet`...
本文将深入探讨Java中的常用集合类,包括ArrayList、LinkedList、HashSet、HashMap等,以及它们的特点和使用场景。 首先,我们来看ArrayList。ArrayList是基于数组实现的集合,它提供了动态数组的功能,允许在列表...