在改一个bug的时刻,把原来的老大写个map.values()改成了map.keyset()。前面通过循环得到一个prepared sql,后面再把对象的数据放入到PreparedStatement中。
下班后,感觉不是很对劲。Map怎么确保得values()和keyset()的顺序是一样的呢?
原来用map都是先取key然后得到value。由于在map上封装了,不能直接取得entryset,只有keyset和values(),getValue(key)。那values()和keyset()中的元素顺序是否对应呢?
首先,写个test,看看顺序是不是一致的:
public class HashMapOrder {
public static void main(String[] args) {
HashMap map = new HashMap();
// map.put(1, "E");
// map.put(2, "D");
// map.put(3, "C");
// map.put(4, "B");
// map.put(5, "A");
map.put(12, "E");
map.put(2, "D");
map.put(31, "C");
map.put(4, "B");
map.put(56, "A");
for(Object key:map.keySet())
System.out.print(key + ", ");
System.out.println();
for(Object value:map.values())
System.out.print(value+", ");
}
}
发现没问题,第一个注释了的代码数据是有序的。输出
1, 2, 3, 4, 5,
E, D, C, B, A,
第二个无序数据输出:
2, 4, 56, 12, 31,
D, B, A, E, C,
也正常!
没问题,查看代码理解如下:
HashMap中存储数据的对象本质是有一个数组!使用Entry[]保存keyvalue对, 然后如果是一样的index会以链表的形式加在entry的next上。
keyset()和value()返回的都是匿名内部类对象,使用iterator迭代器对table的一个迭代!
首先,说明entryset()的来龙气脉,后面values()和keyset()都会用到这个方法。
java.util.HashMap.entrySet()
public Set<Map.Entry<K,V>> entrySet() {
return entrySet0();
}
private Set<Map.Entry<K,V>> entrySet0() {
Set<Map.Entry<K,V>> es = entrySet;
return es != null ? es : (entrySet = new EntrySet());
}
// 内部类,没有static!
private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
public Iterator<Map.Entry<K,V>> iterator() {
return newEntryIterator(); //!!!
}
public boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<K,V> e = (Map.Entry<K,V>) o;
Entry<K,V> candidate = getEntry(e.getKey()); // !!!
return candidate != null && candidate.equals(e);
}
public boolean remove(Object o) {
return removeMapping(o) != null;
}
public int size() {
return size;
}
public void clear() {
HashMap.this.clear();
}
}
java.util.HashMap.getEntry(Object)
final Entry<K,V> getEntry(Object key) {
int hash = (key == null) ? 0 : hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
Iterator<Map.Entry<K,V>> newEntryIterator() {
return new EntryIterator();
}
private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {
public Map.Entry<K,V> next() {
return nextEntry();
}
}
java.util.HashMap.HashIterator.nextEntry()
。。。。。。
再来看keyset()和value()方法,通过iterator迭代entrySet,即获取Entry[]数组中的元素,然后分别取对应的key和value:
java.util.AbstractMap.keySet()
public Set<K> keySet() {
if (keySet == null) {
keySet = new AbstractSet<K>() {
public Iterator<K> iterator() {
return new Iterator<K>() {
private Iterator<Entry<K,V>> i = entrySet().iterator();
public boolean hasNext() {
return i.hasNext();
}
public K next() {
return i.next().getKey(); //!!!
}
public void remove() {
i.remove();
}
};
}
public int size() {
return AbstractMap.this.size();
}
public boolean isEmpty() {
return AbstractMap.this.isEmpty();
}
public void clear() {
AbstractMap.this.clear();
}
public boolean contains(Object k) {
return AbstractMap.this.containsKey(k);
}
};
}
return keySet;
}
public Collection<V> values() {
if (values == null) {
values = new AbstractCollection<V>() {
public Iterator<V> iterator() {
return new Iterator<V>() {
private Iterator<Entry<K,V>> i = entrySet().iterator();
public boolean hasNext() {
return i.hasNext();
}
public V next() {
return i.next().getValue();//!!!
}
public void remove() {
i.remove();
}
};
}
public int size() {
return AbstractMap.this.size();
}
public boolean isEmpty() {
return AbstractMap.this.isEmpty();
}
public void clear() {
AbstractMap.this.clear();
}
public boolean contains(Object v) {
return AbstractMap.this.containsValue(v);
}
};
}
return values;
}
分享到:
相关推荐
HashMap中的值是成对地放置的,即VALUE-KEY.因此我们一般在MAP中取出数据时得根据KEY来取出VALUE.但若我们想出VALUE值,但却不知对应地KEY,这时我们就得先遍历VALUE值,找出对应地KEY值,再根据KEY值取出VALUE值
简单的hashmap key、value方便以后直接用。
简单地说,在keyset方法返回的set上做修改会改变原来hashmap,这也许不是你想要的,于是形成一个隐藏的bug
NULL 博文链接:https://gghaomm.iteye.com/blog/1754487
Map集合的特性:一个key值对应一个value值,key值保持着唯一性,而插入的键值对相同key值会发生覆盖原key值对应的value值。 Map集合中一个key对应一个value,但是一个相同的value值可以对应多个key值 下面我们来根据...
HashMap底层实现原理HashMap与HashTable区别HashMap与HashSet区别。HashMap、HashTable和HashSet是Java中常用的数据结构,它们的底层实现原理以及区别如下:HashMap底层实现原理: HashMap基于哈希表(HashTable)...
hashmap与hashtable区别 主要是应用于存值的数值对
今天小编就为大家分享一篇关于Java源码解析HashMap的keySet()方法,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
初级程序员面试经常问道的问题,HashMap与HashTable区别,希望有帮助
HashMap是一个散列桶(数组和链表),它存储的内容是键值对(key-value)映射HashMap采用了数组和链表的数据结构,能在查询和修改方便继承了数组的线性查找和链表的寻址修改HashMap是非synchronized,所以HashMap很快...
- KeySet 内部类 - Values 内部类 - EntrySet 内部类 - HashMap 1.7 的底层结构 - HashMap 1.8 的底层结构 - HashMap 重要属性 - HashMap 构造函数 - 讲一讲 HashMap put 的全过程 - Hash 函数 - 扩容机制...
hashmap实例 hashmap实例hashmap实例hashmap实例
涵盖绝大部分HashMap与ConcurrentHashMap的面试题 附带答案
hashmap相关的面试题
HashMap数据结构,HashMap的构造方法,HashMap的put,HashMap的get
HashMap介绍和使用
HashMap允许将null作为一个entry的key或者value,而Hashtable不允许。 HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解。 Hashtable继承自Dictionary类...
Java8HashMap键与Comparable接口编程开发技术共3页.pdf.zip
HashTable不支持空键值对! 而HashMap支持空键值对!
HashMap存放.doc