在改一个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`中,我们通过键(Key)来访问其对应的值(Value)。因此,理解如何获取`HashMap`中的“索引”,实际上是指如何有效地遍历`HashMap`以及获取其键值对。 #...
6. **遍历HashMap**:有两种方式遍历HashMap,一是通过`entrySet()`获取键值对的迭代器,二是通过`keySet()`获取键的迭代器再获取对应的值。 ```java for (Map.Entry, String> entry : map.entrySet()) { System....
9. 其他特性:HashMap还提供了containsKey()、containsValue()、clear()等方法,以及keySet()、values()和entrySet()这三个集合视图,分别用于获取键集合、值集合和键值对集合,方便进行遍历和操作。 总的来说,...
6. **迭代器遍历**:尽管遍历顺序不确定,但`HashMap`提供`keySet()`, `values()`和`entrySet()`方法来遍历键、值和键值对。 下面是一些关于`HashMap`的基本操作: - **插入键值对**:使用`put()`方法插入键值对,...
HashMap 是 Java 语言中最常用的集合类之一,它实现了 Map 接口,提供了 put、get、keySet 等常用方法来存储和检索数据。本文将详细介绍 HashMap 类的使用,包括其常用方法、特点和应用场景。 一、HashMap 的基本...
与`keySet()`不同的是,`entrySet()`允许我们同时访问键和值,而无需额外的`get()`操作。这在性能上通常更优,尤其是在频繁访问键值对的场景下。下面是一个使用`entrySet()`遍历`HashMap`的示例: ```java Map, ...
keySet()方法提供了一个包含所有键的Set集合,通过遍历这个Set集合,我们可以获取到HashMap中的每一个键,然后再通过键去get()对应的值。这种方式比较适合只需要使用键的场景。 **优点**:如果只需要键,这种方法...
- **迭代器方式**:HashMap提供了`keySet()`、`values()`和`entrySet()`方法,返回相应的Set视图。可以使用迭代器遍历这些集合,分别获取键集、值集和键值对集。 - **foreach循环**:Java 5引入了增强的for循环...
当查找某个键对应的值时,HashMap首先计算键的哈希码,然后在相应的桶中搜索,如果找到多个键值对,就遍历链表直到找到匹配的键。 HashMap的特点: 1. 不保证元素的顺序,插入顺序和迭代顺序可能会不同,因为哈希表...
- **初始容量与加载因子**:HashMap有初始容量和加载因子两个参数,当元素数量达到容量*加载因子时,HashMap会自动扩容。 - **null键和值**:HashMap允许一个null键和任意数量的null值。 **HashMap的方法:** - `...
HashMap是基于哈希表实现的,通过哈希函数计算键的存储位置,以此来快速存取对应的值。以下是HashMap的一些关键知识点: 1. **HashMap的定义与实现**: HashMap实现了Map接口,继承自AbstractMap类。Map接口定义了...
HashMap提供了两种遍历方式:通过迭代器(Iterator)按照插入顺序遍历,或者通过键集(keySet)、值集(values)或键值对集(entrySet)按照哈希顺序遍历。由于HashMap的无序性,不保证插入顺序与遍历顺序一致。 8....
HashMap的`keySet()`方法返回所有键的集合,可以通过遍历这个集合来访问每个键,然后使用`get()`方法获取对应的值。这种方式也是比较常见的遍历方法,如下所示: ```java HashMap, String> map = new HashMap(); //...
Java中的HashMap是基于哈希表实现的Map接口的一个实现,它允许将键映射到相应的值。HashMap在Java集合框架中扮演着重要角色,提供快速的查找、插入和删除操作,平均时间复杂度为O(1)。下面将详细介绍HashMap的特点、...
Map的keySet()方法可以获取Map中的所有Key,然后根据Key获取对应的Value。下面是一个简单的示例代码: ```java for (String key : map.keySet()) { String value = map.get(key); System.out.println(key + " " + ...
* containsValue操作:用于判断HashMap中是否包含指定的值,例如`map.containsValue("Barcelona")`。 * remove操作:用于删除HashMap中指定的键值对,例如`map.remove(5)`。 * clear操作:用于清空HashMap中的所有...
在标准的HashMap中,查找键对应的值是常见的操作,但查找具有特定值的所有键则不太常见,而DoubleAccessMap就是为了解决这个问题而设计的。 在Java中,HashMap是一个存储键值对的数据结构,其中每个键都是唯一的,...
由于Set接口实现了Iterable接口,我们可以使用for-each循环来遍历KeySet,然后通过map.get(key)获取对应的值。这种方式可以分别获取键和值,但无法同时获取键值对。 2. **方式二:使用Values方法** Values方法返回...