首先点开HashMap的源码,看下介绍
继承的是Map,就是个键值对的集合,key和value支持null。存储的数据是无序的,而且这个不是线程安全的,多个线程同时操作,可能会发生问题。
/**
* HashMap is an implementation of {@link Map}. All optional operations are supported.
*
* All elements are permitted as keys or values, including null.
*
*
Note that the iteration order for HashMap is non-deterministic. If you want
* deterministic iteration, use {@link LinkedHashMap}.
*
*
Note: the implementation of {@code HashMap} is not synchronized.
* If one thread of several threads accessing an instance modifies the map
* structurally, access to the map needs to be synchronized. A structural
* modification is an operation that adds or removes an entry. Changes in
* the value of an entry are not structural changes.
*
*
The {@code Iterator} created by calling the {@code iterator} method
* may throw a {@code ConcurrentModificationException} if the map is structurally
* changed while an iterator is used to iterate over the elements. Only the
* {@code remove} method that is provided by the iterator allows for removal of
* elements during iteration. It is not possible to guarantee that this
* mechanism works in all cases of unsynchronized concurrent modification. It
* should only be used for debugging purposes.
*
* @param the type of keys maintained by this map
* @param the type of mapped values
*/
public class HashMap extends AbstractMap implements Cloneable, Serializable
下边通过代码测试下:
HashMap hashMap=new HashMap<>();
hashMap.put("key1", "value1");
hashMap.put("key2", "value2");
hashMap.put("key3", "value3");
hashMap.put("key4", "value4");
hashMap.put(null, "value4");
hashMap.put("key5", null);
Set keys=hashMap.keySet();
for(String key:keys) {
System.err.println(key);
}
System.err.println("=========");
Collection values=hashMap.values();
for(String value:values) {
System.err.println(value);
}
//打印结果
key1
null
key2
key5
key3
key4
=========
value1
value4
value2
null
value3
value4
可以看到打印结果和我们存进去的顺序是不一样的。
下边看下put方法,返回值是上一个关联的value
* @return the value of any previous mapping with the specified key or
* {@code null} if there was no such mapping.
*/
@Override public V put(K key, V value) {
if (key == null) {
return putValueForNullKey(value);//看这里,key是可以为空的
}
//下面这些代码是,循环查看有没有一样的key,有的话把value值修改为当下的
int hash = Collections.secondaryHash(key);
HashMapEntry[] tab = table;
int index = hash & (tab.length - 1);
for (HashMapEntry e = tab[index]; e != null; e = e.next) {
if (e.hash == hash && key.equals(e.key)) {
preModify(e);
V oldValue = e.value;
e.value = value;
return oldValue;
}
}
// No entry for (non-null) key is present; create one,没有找到一样的key,那就新建一个存进去
modCount++;
if (size++ > threshold) {
tab = doubleCapacity();
index = hash & (tab.length - 1);
}
addNewEntry(key, value, hash, index);
return null;
}
这里需要看下HashMapEntry里都有啥,可以看到除了key,value,hashcode,还有一个next的东西,这个是啥?
static class HashMapEntry implements Entry {
final K key;
V value;
final int hash;
HashMapEntry next;
HashMapEntry(K key, V value, int hash, HashMapEntry next) {
this.key = key;
this.value = value;
this.hash = hash;
this.next = next;
}
看这里添加新元素的代码,说实话,这个index是key的hashcode操作来的,看里边各种左移右移的,都晕了,不管了。
void addNewEntry(K key, V value, int hash, int index) {
table[index] = new HashMapEntry(key, value, hash, table[index]);
}
看一下数据的获取
public Set> entrySet() {
Set> es = entrySet;
return (es != null) ? es : (entrySet = new EntrySet());
}
@Override public Set keySet() {
Set ks = keySet;
return (ks != null) ? ks : (keySet = new KeySet());
}
@Override public Collection values() {
Collection vs = values;
return (vs != null) ? vs : (values = new Values());
}
可以看到entry和key返回的都是Set,而values返回的Collection,为啥,因为前者不能有重复元素,后者可以。
/**
* A {@code Set} is a data structure which does not allow duplicate elements.
*
* @since 1.2 set没有重复元素,Collection有,所以也能看出hasmap的key是不能重复的
*/
public interface Set extends Collection
另外,我们学的时候知道这HashMap数据是无序的,而LinkedHashMap是有序的,为啥了,我们都知道他们是继承关系,
然后看下里边的方法,有序无语和put是没啥关系的。关键就是取的时候。
public class LinkedHashMap
extends HashMap
implements Map
对比下两者取的方法,返回的Set不一样
//HashMap的
public Set> entrySet() {
Set> es = entrySet;
return (es != null) ? es : (entrySet = new EntrySet());
}
//LinkedHashMap的
public Set> entrySet() {
Set> es;
return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
}
其实是这里不同,他们两个存储的实体类有点区别,linked的多了2个before和after。
static class Entry extends HashMap.Node {
Entry before, after;
Entry(int hash, K key, V value, Node next) {
super(hash, key, value, next);
}
}
看下hashmap的put方法
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
/**
* Implements Map.put and related methods
*
* @param hash hash for key
* @param key the key
* @param value the value to put
* @param onlyIfAbsent if true, don't change existing value
* @param evict if false, the table is in creation mode.
* @return previous value, or null if none
*/
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node[] tab; Node p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);//这里是新建一个Node
else
//HashMap里newNode是这样的
Node newNode(int hash, K key, V value, Node next) {
return new Node<>(hash, key, value, next);
}
//LinkedHashMap,可以看到它对before和after进行了赋值
Node newNode(int hash, K key, V value, Node e) {
LinkedHashMap.Entry p =
new LinkedHashMap.Entry(hash, key, value, e);
linkNodeLast(p);
return p;
}
private void linkNodeLast(LinkedHashMap.Entry p) {
LinkedHashMap.Entry last = tail;
tail = p;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
}
这样就了解了,比如第一条数据p0存进来,这时候head,tail都是空的,所以会走if那里,结果就是
tail=p0,head=p0;
然后我们继续存第二条p1,这时候,head和tail都是p0,也就是不为空,会走else方法,结果就是
tail=p1, p1的before=p0,p0的after=p1
后边的就一样的道理,before存的是上一条数据,after存的是后一条数据。
所以这样就有序了,
可以看下它取数据的代码
abstract class LinkedHashIterator {
LinkedHashMap.Entry next;
LinkedHashMap.Entry current;
int expectedModCount;
LinkedHashIterator() {
next = head;//head就是我们存的第一条数据
expectedModCount = modCount;
current = null;
}
public final boolean hasNext() {
return next != null;
}
final LinkedHashMap.Entry nextNode() {
LinkedHashMap.Entry e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
current = e;
next = e.after;//after就是上边分析的,下一条数据拉。
return e;
}
最后看下linkedHashMap里有个boolean到底干啥的,下面是源码的英文说明,举例例子:
true的话,就是我们常说的文章的修改时间排序一样,false就按照文章的创建时间排序一样。
/**
* The iteration ordering method for this linked hash map: true
* for access-order, false for insertion-order.
*
* @serial
*/
final boolean accessOrder;
比如还是上边的代码,我们修改这个accessOrder为true,
HashMap hashMap=new LinkedHashMap(2,0.75f,true);
hashMap.put("key1", "value1");
hashMap.put("key2", "value2");
hashMap.put("key3", "value3");
hashMap.put("key2", "value22");
打印出来的顺序就成了 key1,key3,key2拉,嗯,因为key2最后修改了一下,所以它跑到key3后边去了
顺道看下HashSet,LinkedHashSet,可以发现,他们里边的存储就是HashMap和LinkedHashMap
public HashSet() {
map = new HashMap<>();
}
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
private static final Object PRESENT = new Object();
没看懂
里边的index,hashcode我是看晕了,左移,右移,又与操作,最后得出来的index,完全看不懂啊,嗯,说着说,完全不想去看懂,
自己简单看完源码,又百度搜了下,看这篇好像还不错,没仔细看。也许以后需要再看
http://blog.csdn.net/justloveyou_/article/details/71713781