一.遍历
遍历的方法:
- keySet()。
- entrySet()。
从代码来看,entrySet的遍历方式要比keySet的遍历方式少了一次根据Key查找Value操作,应该更加高效一些。
HashMap 中的modCount属性,表示的是该hashMap被修改的次数,此属性主要是在遍历功能里面使用。
modCount属性与ConcurrentModificationException 异常有关。
迭代器的modCount和expectedModCount的值不一致。
单线程中该异常出现的原因是:对一个集合遍历的同时,有对该集合进行了增删的操作。导致HashMap的modCount和expectedModCount的值不一致。
多线程中更容易出现该异常,当你在一个线程中对一数据集合进行遍历,正赶上另外一个线程对该数据集合进行增删操作。
二.序列化
HashMap实现了Serializable接口,表示它能够被序列化。但是存储数据的table变量前面加上了transient关键字,这个关键字的意思是在序列化的时候不用管这个变量。那究竟是为什么呢?因为不同的JVM针对对同一个对象产生的hashcode值不同,导致在不同JVM反序列化时会可能会得到不同的对象。
而HashMap自己实现了writeObject(ObjectOutputStream)和readObject(ObjectInputStream)这两个方法。看到网上有人说在实现序列化的时候,如果该类实现了writeObject和readObject这两个方法那么就会调用该类的实现,如果没有的话就会使用defaultWriteObject()和defaultReadObject(),而HashMap就是自己实现了writeObject和readObject方法,自己对table做了处理。
private void writeObject(java.io.ObjectOutputStream s)
throws IOException
{
Iterator<Map.Entry<K,V>> i =
(size > 0) ? entrySet0().iterator() : null;
// Write out the threshold, loadfactor, and any hidden stuff
s.defaultWriteObject();
// Write out number of buckets
s.writeInt(table.length);
// Write out size (number of Mappings)
s.writeInt(size);
// Write out keys and values (alternating)
if (i != null) {
while (i.hasNext()) {
Map.Entry<K,V> e = i.next();
s.writeObject(e.getKey());
s.writeObject(e.getValue());
}
}
}
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException
{
// Read in the threshold, loadfactor, and any hidden stuff
s.defaultReadObject();
// Read in number of buckets and allocate the bucket array;
int numBuckets = s.readInt();
table = new Entry[numBuckets];
init(); // Give subclass a chance to do its thing.
// Read in size (number of Mappings)
int size = s.readInt();
// Read the keys and values, and put the mappings in the HashMap
for (int i=0; i<size; i++) {
K key = (K) s.readObject();
V value = (V) s.readObject();
putForCreate(key, value);
}
}