文章标题 【Java源码浅析】关于HashMap和HashSet的异同和源码分析
来源:互联网 发布:mac连不上wifi 编辑:程序博客网 时间:2024/06/06 14:07
最近学了JAVA之后,对JAVA源码实现很感兴趣,于是就在自己的Eclipse里看JAVA里的一些常用的类的源码实现,自己水平也不是很高,有不懂的代码还是要去看别人写的博客,我写的这篇文章也是看了别人的博客后,加上自己看了源码后的理解而作,既是希望自己能从此掌握这两个类的实现,也能帮助那些渴望成为编程大牛的孩子。大家有不理解的可以看这篇文章 https://www.baidu.com/link?url=IqZUK4wSjRAZ-yDH2wgp_x3uosAcN1bFUv7GYaQk4DStjeU559QtWuUsHAu9WViOKJXaaW3qJnBJv3KH9jRI2nhOdw-zjOi-GA4OspLHYUK&wd=&eqid=cf09827d00034226000000035991cae8
HashMap和HashSet是java里很常用的两个类,他们有
相同之处
1:都是用Hash算法来存储元素的值
2:查找存取的性能都很好(当然比数组还是稍微差一些)
3:存储的值都允许为null
4:都不是线程安全的
5:都不维护元素的顺序,也就是说,是乱序存放的
6:都是collection框架的一部分
不同之处
1:HashSet里的value不允许重复,但是HashMap的value是允许重复的
2:HashMap是以键值对来存储的,而HashSet仅仅是存放值
3:HashMap实现的是Map接口,HashSet实现的是Set接口
4:HashMap使用键对象来计算Hashcode,HashSet使用值对象来计算hashcode(因为它只存放值,所以只能用值来计算hashcode)
下面就是具体的分析源码了,先把源码贴上,我们边看源码边分析。先分析HashMap(hashmap的实现原理图接我建议先看这篇博文,我觉得讲的很清楚 http://blog.csdn.net/eson_15/article/details/51158865?locationNum=2&fps=1)
/*HashMap 继承的是AbstractMap,它实现了Map, Cloneable, Serializable 三个类*/public class HashMap extends AbstractMap implements Map, Cloneable, Serializable{ /*DEFAULT_INITIAL_CAPACITY = 16 默认容量为16*/ static final int DEFAULT_INITIAL_CAPACITY = 16; static final int MAXIMUM_CAPACITY = 1073741824; /*默认的负载因子的值*/ static final float DEFAULT_LOAD_FACTOR = 0.75F; /*说一下 transient 。transient是Java语言的关键字,用来表示一个域不象串行化的一部分。当持久化对象时,可能有一个特殊的对象数据成员,我们不想serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。然而非transient型的变量是被包括进去的。*/ transient Entry[] table;/* table 是Entry[]数组变量,也就是键值对类型的数组,一个可以对应一个value*/ transient int size; int threshold; /* 极限容量*/ final float loadFactor; /*负载因子*/ transient volatile int modCount; /*用来记录对map的操作次数,这个变量特别重要*/ private transient Set entrySet = null; private static final long serialVersionUID = 362498820763181265L; /*静态的Entry类,实现Map.Entry,里面就定义了,key,value,next,hash我们需要用的变量,key,value不说了,next变量相当于一个指针,在用 Iterator 遍历时会发挥很大的作用*/ static class Entry implements Map.Entry { final Object key; Object value; Entry next; final int hash; /*Entry 的构造函数*/ Entry(int i, Object object, Object object_0_, Entry entry_1_) { value = object_0_; next = entry_1_; key = object; hash = i; } /*得到map里存储的key值*/ public final Object getKey() { return key; } /*得到value值*/ public final Object getValue() { return value; } /*设置value值*/ public final Object setValue(Object object) { Object object_2_ = value; /*用一个变量来保存旧的值*/ value = object; /*设置新的值*/ return object_2_; /*返回旧值*/ } /*判断两个对象是否相等的方法*/ public final boolean equals(Object object) { if (!(object instanceof Map.Entry)) return false; /*首先判断类型是否相等,不相等直接返回false*/ /*强制转换object为Entry对象类型,用entry_3_ 变量表示*/ Map.Entry entry_3_ = (Map.Entry) object; Object object_4_ = getKey(); /*用getKey方法得到key值(这是用equals方法的那个对象的key值,而不是object的key值)*/ /*这才是object的key值,entry_3_ 表示的就是object*/ Object object_5_ = entry_3_.getKey(); /*判断key值是否相等(object_4_ == object_5_), (object_4_ != null && object_4_.equals(object_5_))key值不能为null且要相等,否则就没必要比较value值了*/ if (object_4_ == object_5_ || object_4_ != null && object_4_.equals(object_5_)) { /*就可以比较value值是否相等,逻辑与比较key值相同*/ Object object_6_ = getValue(); Object object_7_ = entry_3_.getValue(); if (object_6_ == object_7_ || object_6_ != null && object_6_.equals(object_7_)) return true; } return false; } /*根据key值和value值来计算hash值,来定位此对象在hashmap中的位置*/ public final int hashCode() { return ((key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode())); } /*toString() 方法,没什么好说的*/ public final String toString() { return new StringBuilder().append(getKey()).append("=").append (getValue()).toString(); } void recordAccess(HashMap hashmap) { /* empty */ } void recordRemoval(HashMap hashmap) { /* empty */ } } /*内部类,定义EntryIterator 迭代器和一些其他方法,是可以被hashmap类直接访问的,从名字可以知道,它是用来迭代Entry类型对象的迭代器*/ private final class EntryIterator extends HashIterator { final HashMap this$0 = HashMap.this; (HashMap.this表示引用的是HashMap这个类的实例,不这样声明编译器会不知道引用的是哪个实例) /*直接继承父类的EntryIterator()*/ private EntryIterator() { super(); } /*next()方法,迭代器时会使用,是实现迭代器的重要方法*/ public Map.Entry next() { return nextEntry(); } public volatile Object next() { return next(); } EntryIterator(ANONYMOUS CLASS java.util.HashMap$1 var_1) { this(); } } /*EntrySet类,将Entry对象封装成一个Set,这样可以用来作遍历hashmap集合,速度很快*/ private final class EntrySet extends AbstractSet { final HashMap this$0 = HashMap.this; /*使用父类的构造函数*/ private EntrySet() { super(); } /*EntrySet的迭代器*/ public Iterator iterator() { return this$0.newEntryIterator(); } /*判断是否包含此object对象*/ public boolean contains(Object object) { if (!(object instanceof Map.Entry)) return false; /*同样是先判断类型是否相等*/ Map.Entry entry = (Map.Entry) object; /*通过getEntry()方法通过entry.getKey()得到Entry对象*/ Entry entry_8_ = this$0.getEntry(entry.getKey()); /*调用之前的equals方法来判断是否相等,相等则返回true*/ return entry_8_ != null && entry_8_.equals(entry); } /*调用hashmap.removeMapping(object)方法,如果成功删除,则放回true,否则object不在keyset里,则放回false*/ public boolean remove(Object object) { return this$0.removeMapping(object) != null; } /*整个map的大小*/ public int size() { return this$0.size; } /*调用hashmap的clear()方法,这个方法在下面会说到*/ public void clear() { this$0.clear(); } EntrySet(ANONYMOUS CLASS java.util.HashMap$1 var_1) { this(); } } /*真正到了重要的地方,这个类特别重要,也是个迭代类,是内部抽象类,这个类的方法常常拿来做hashmap的迭代*/ private abstract class HashIterator implements Iterator { Entry next; /*entry类型的变量,是用来保存下一个迭代对象的 指针 */ int expectedModCount; /* 这个int 型变量是跟前面 modCount 对应的,他们一定要相等,不然就会报错,他们是用来记录对map集合的操作次数,即增删改的次数*/ int index; /*hash 下标,标识map中元素的位置*/ Entry current; /*迭代过程中当前的迭代对象*/ final HashMap this$0 = HashMap.this; /* 要记得它还是当前这个hashmap的引用实例*/ /*构造函数 注意 expectedModCount = modCount; 是要相等的 */ HashIterator() { super(); expectedModCount = modCount; if (size > 0) { Entry[] entrys = table; while (index < entrys.length && (next = entrys[index++]) == null) { /* empty */ /*为什么里面是空的,我也不是太清楚,我看别人博客说的是,这是为了让你自己写你需要的实现,while里的条件也不难理解*/ } } } /* hasNext 方法,是不是很简单?只要还有next指针,就可以继续遍历,否则返回false*/ public final boolean hasNext() { return next != null; } /*这个类返回Entry类型的对象 */ final Entry nextEntry() { / * 先判断modCount == expectedModCount 是否相等,如果不等,就会抛出异常 ConcurrentModificationException()*/ if (this$0.modCount != expectedModCount) throw new ConcurrentModificationException(); /*将next对象赋给 entry变量*/ Entry entry = next; /*判断是否为null,为null表示没有这个元素存在map里*/ if (entry == null) throw new NoSuchElementException(); /*以上的判断都通过了,就可以真正进行nextEntry 的判断了,(next = entry.next) == null 因为 hashmap里存放数据是不连续的,如果下一个指针所指的entry对象为null,就通过下面的代码来找到下一个不为null的对象,当entry.next为空时,就要循环找到下一个不为空的entry对象,entry.next不为null,则会跳过这段代码*/ if ((next = entry.next) == null) { Entry[] entrys = this$0.table; /*while 的作用,当遇到不为null的entry对象就跳出循环,并且赋给了 next 指针 要是一直是null,那么next指针也是null,index标识当前entry对象在进入循环时的位置,并且会执行index++操作*/ while (index < entrys.length && (next = entrys[index++]) == null) { /* empty */ } } /*当前迭代的对象是entry*/ current = entry; return entry; /*返回entry*/ } /* 删除操作*/ public void remove() { /*当前要删除的对象不能为null*/ if (current == null) throw new IllegalStateException(); /*modCount ,expectedModCount 一定要相等*/ if (this$0.modCount != expectedModCount) throw new ConcurrentModificationException(); /*先得到key*/ Object object = current.key; /*将它设为null,这样GC就会回收它*/ current = null; /*调用此方法,就能以key来删除 entry对象*/ this$0.removeEntryForKey(object); /*删除操作后要再次令 expectedModCount = this$0.modCount*/ expectedModCount = this$0.modCount; } } /*这是以key来作迭代的 内部类,继承 HashIterator 原理都差不多*/ private final class KeyIterator extends HashIterator { final HashMap this$0 = HashMap.this; private KeyIterator() { super(); } /*得到下一个key*/ public Object next() { return nextEntry().getKey(); } KeyIterator(ANONYMOUS CLASS java.util.HashMap$1 var_1) { this(); } } /* keyset 也就是所有的key的集合,也可以拿来遍历map的key的集合*/ private final class KeySet extends AbstractSet { final HashMap this$0 = HashMap.this; private KeySet() { super(); } public Iterator iterator() { return this$0.newKeyIterator(); } public int size() { return this$0.size; } /*调用containsKey(object) 来判断是否包含,containsKey(object) 在后面会说*/ public boolean contains(Object object) { return this$0.containsKey(object); } /*同上的remove方法的逻辑*/ public boolean remove(Object object) { return this$0.removeEntryForKey(object) != null; } public void clear() { this$0.clear(); } KeySet(ANONYMOUS CLASS java.util.HashMap$1 var_1) { this(); } } /*同keyIterator 的实现原理和思路*/ private final class ValueIterator extends HashIterator { final HashMap this$0 = HashMap.this; private ValueIterator() { super(); } public Object next() { return nextEntry().value; } ValueIterator(ANONYMOUS CLASS java.util.HashMap$1 var_1) { this(); } } private final class Values extends AbstractCollection { final HashMap this$0 = HashMap.this; private Values() { super(); } public Iterator iterator() { return this$0.newValueIterator(); } public int size() { return this$0.size; } public boolean contains(Object object) { return this$0.containsValue(object); } public void clear() { this$0.clear(); } Values(ANONYMOUS CLASS java.util.HashMap$1 var_1) { this(); } } /*终于找到hashmap的构造方法了。i 是设置 entry[] 数组的大小, i不能小于0,也不能大于1073741824,f是负载因子的大小*/ public HashMap(int i, float f) { if (i < 0) throw new IllegalArgumentException (new StringBuilder().append ("Illegal initial capacity: ").append (i).toString()); if (i > 1073741824) i = 1073741824; if (f <= 0.0F || Float.isNaN(f)) throw new IllegalArgumentException(new StringBuilder().append ("Illegal load factor: ") .append (f).toString()); int i_9_; for (i_9_ = 1; i_9_ < i; i_9_ <<= 1) { /* empty */ } loadFactor = f; threshold = (int) ((float) i_9_ * f); table = new Entry[i_9_]; /*初始化的方法,是空的*/ init(); } /*这个大家都能看懂吧*/ public HashMap(int i) { this(i, 0.75F); } /*默认的构造方法,如果不加参数,就默认这么设置*/ public HashMap() { loadFactor = 0.75F; threshold = 12; table = new Entry[16]; init(); } /*这个构造方法比较复杂,好像也不常用*/ public HashMap(Map map) { this(Math.max((int) ((float) map.size() / 0.75F) + 1, 16), 0.75F); /*注意这个方法,后面会说到*/ putAllForCreate(map); } void init() { /* empty */ } /*这就是计算hash值的方法,想深入研究的可以去查查实现原理,我不是太懂*/ static int hash(int i) { i ^= i >>> 20 ^ i >>> 12; return i ^ i >>> 7 ^ i >>> 4; } /*这个方法计算出该entry对象在table数组里存放的位置, i_10_ 变量将要存的是table数组的长度,传入table数组的长度就不会使计算出的位置超越数组的长度*/ static int indexFor(int i, int i_10_) { return i & i_10_ - 1; } public int size() { return size; } /*这个方法也是很简单的,size大于0,就不是空的*/ public boolean isEmpty() { return size == 0; } /*get方法会根据object(实际上它是key的值)得到所存贮的值*/ public Object get(Object object) { if (object == null) /*为null时,用getForNullKey() 方法得到它的值*/ return getForNullKey(); int i = hash(object.hashCode()); /*得到hash值,即索引*/ /*用for循环来循环此table[indexFor(i, table.length)]处是否存在链表,有链表则遍历找出要找的key和它的值*/ for (Entry entry = table[indexFor(i, table.length)]; entry != null; entry = entry.next) { Object object_11_; /*if条件里是要对比key值和计算出的hash值的,最后还得用equals方法进行比较,才能真正返回value值*/ if (entry.hash == i && ((object_11_ = entry.key) == object || object.equals(object_11_))) return entry.value; } return null; } /*当key为空时,调用此方法得到对应value*/ private Object getForNullKey() { /*为什么从0开始遍历呢?因为hashmap里默认将key=null的key-value对放在table[0]处,for循环用来检查是否有链表存在,有则遍历得到第一个key为null的值*/ for (Entry entry = table[0]; entry != null; entry = entry.next) { if (entry.key == null) return entry.value; } return null; } /*通过key值来判断此key是否包含在table数组里*/ public boolean containsKey(Object object) { return getEntry(object) != null; } /*getEntry方法,很重要,在很多方法里都调用了它*/ final Entry getEntry(Object object) { /*首先还是先计算它的hash值,它是用来在indexFor(i, table.length)方法里定位此key在table数组里的地址的*/ int i = object == null ? 0 : hash(object.hashCode()); /*此for循环的作用和之前的一样,大家很容易看懂的*/ for (Entry entry = table[indexFor(i, table.length)]; entry != null; entry = entry.next) { Object object_12_; if (entry.hash == i && ((object_12_ = entry.key) == object || object != null && object.equals(object_12_))) return entry; } return null; } /*hashmap里的put方法,大家经常用,现在看看是怎么实现的*/ public Object put(Object object, Object object_13_) { /*先判断key是否为空,为空则用另外的方法来put它,即putForNullKey(object_13_) 方法*/ if (object == null) return putForNullKey(object_13_); /*一样得到hash值*/ int i = hash(object.hashCode()); int i_14_ = indexFor(i, table.length); /*定位在table数组的位置*/ /*判断此位置是否有链表,此段代码会判断是否已经有相同的key值存在,如果已经有了,会覆盖value值,没有则会在此位置插入一个entry对象*/ for (Entry entry = table[i_14_]; entry != null; entry = entry.next) { Object object_15_; if (entry.hash == i && ((object_15_ = entry.key) == object || object.equals(object_15_))) { Object object_16_ = entry.value; entry.value = object_13_; /*替换value值*/ entry.recordAccess(this); return object_16_; /*会返回旧值*/ } } /*如果没有已经存在的key值,会直接执行下面的代码*/ modCount++; /*操作标识数+1*/ addEntry(i, object, object_13_, i_14_); /*新加了一个entry对象*/ return null; } /*当key值为空时,object代表的要插入的value值*/ private Object putForNullKey(Object object) { for (Entry entry = table[0]; entry != null; entry = entry.next) { /*也替换key为null的entry对象的value值*/ if (entry.key == null) { Object object_17_ = entry.value; entry.value = object; entry.recordAccess(this); return object_17_; } } /*前面的代码执行后没有找到null的key,则新插入一个新entry对象*/ modCount++; addEntry(0, null, object, 0); return null; } /*这个方法实现原理和前面的方法相同*/ private void putForCreate(Object object, Object object_18_) { int i = object == null ? 0 : hash(object.hashCode()); int i_19_ = indexFor(i, table.length); for (Entry entry = table[i_19_]; entry != null; entry = entry.next) { Object object_20_; if (entry.hash == i && ((object_20_ = entry.key) == object || object != null && object.equals(object_20_))) { entry.value = object_18_; return; } } createEntry(i, object, object_18_, i_19_); } /*和上面的putAllForCreate方法是同一个方法,只是传入的是map*/ private void putAllForCreate(Map map) { /*用iterator迭代器来迭代entrySet()集合里的entry对象*/ Iterator iterator = map.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); putForCreate(entry.getKey(), entry.getValue()); } } /*重置table数组的大小*/ void resize(int i) { Entry[] entrys = table; int i_21_ = entrys.length; if (i_21_ == 1073741824) threshold = 2147483647; /*threshold=i_21*2-1 ,即如果table数组的大小已经达到1073741824了,就扩容*/ else { / *不然,就按传入的i来重新创建Entry[]数组*/ Entry[] entrys_22_ = new Entry[i]; transfer(entrys_22_); /*此方法是重新复制table数组*/ table = entrys_22_; /*将entrys_22_新数组的引用地址赋给table数组*/ threshold = (int) ((float) i * loadFactor); } } /*这就是上面的transfer方法的实现*/ void transfer(Entry[] entrys) { Entry[] entrys_23_ = table; /*这是没复制前的table*/ int i = entrys.length; /*for循环遍历table,并将table里的entry对象存入entrys数组里*/ for (int i_24_ = 0; i_24_ < entrys_23_.length; i_24_++) { Entry entry = entrys_23_[i_24_]; if (entry != null) { entrys_23_[i_24_] = null; /*将它变成null*/ do { Entry entry_25_ = entry.next; int i_26_ = indexFor(entry.hash, i); /*定位在entrys数组里的位置*/ entry.next = entrys[i_26_]; entrys[i_26_] = entry; /*复制操作,将entry赋给entrys[i_26_]*/ entry = entry_25_; /*将原来的entry.next赋给entry,用来作while循环*/ } while (entry != null); } } } /*将map里的对象全放进hashmap里*/ public void putAll(Map map) { int i = map.size(); /*判断map的对象的多少*/ /*对i的值进行判断,这是有必要的*/ if (i != 0) { if (i > threshold) { int i_27_ = (int) ((float) i / loadFactor + 1.0F); if (i_27_ > 1073741824) i_27_ = 1073741824; int i_28_; for (i_28_ = table.length; i_28_ < i_27_; i_28_ <<= 1) { /* empty */ } if (i_28_ > table.length) resize(i_28_); } /*用迭代器来迭代put每一个元素进hashmap*/ Iterator iterator = map.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); put(entry.getKey(), entry.getValue()); } } } /*删除操作*/ public Object remove(Object object) { Entry entry = removeEntryForKey(object); return entry == null ? null : entry.value; } /*删除操作具体实现*/ final Entry removeEntryForKey(Object object) { /*得到hash值*/ int i = object == null ? 0 : hash(object.hashCode()); int i_29_ = indexFor(i, table.length); /*table 数组里object key值对应的地址*/ Entry entry = table[i_29_]; /*得到key对应的那个对象*/ Entry entry_30_; Entry entry_31_; /*还是在遍历当前位置是否有链表存在,有的话就遍历判断*/ for (entry_31_ = entry; entry_31_ != null; entry_31_ = entry_30_) { entry_30_ = entry_31_.next; /*entry_30_存链表上当前entry对象的下一个对象的指针*/ Object object_32_; if (entry_31_.hash == i && ((object_32_ = entry_31_.key) == object || object != null && object.equals(object_32_))) { modCount++; /*删除操作后要modCount++*/ size--; /*大小要减一*/ if (entry == entry_31_) /*如果要删除的是当前的第一个entry对象*/ table[i_29_] = entry_30_; /*则将entry_31_.next存在table[i_29_]中,即将原来是在链表头的entry对象的下一个对象移到表头来,因为当前在表头的entry对象要被删除了*/ else entry.next = entry_30_; /*不是当前的第一个entry对象*/ entry_31_.recordRemoval(this); return entry_31_; } entry = entry_31_; } return entry_31_; /*返回删除的entry对象的value*/ } /*和上面的removeEntryForKey 原理类似*/ final Entry removeMapping(Object object) { if (!(object instanceof Map.Entry)) /*先判断类型是否相同*/ return null; Map.Entry entry = (Map.Entry) object; /*此传入的object就是一个对象类型了,强制转换成entry类型*/ Object object_33_ = entry.getKey(); /*得到key*/ /*得到hash值*/ int i = object_33_ == null ? 0 : hash(object_33_.hashCode()); /*得到在table数组里的定位*/ int i_34_ = indexFor(i, table.length); Entry entry_35_ = table[i_34_]; Entry entry_36_; Entry entry_37_; /*实现原理和上面的方法一致,就不细说了*/ for (entry_37_ = entry_35_; entry_37_ != null; entry_37_ = entry_36_) { entry_36_ = entry_37_.next; if (entry_37_.hash == i && entry_37_.equals(entry)) { modCount++; size--; if (entry_35_ == entry_37_) table[i_34_] = entry_36_; else entry_35_.next = entry_36_; entry_37_.recordRemoval(this); return entry_37_; } entry_35_ = entry_37_; } return entry_37_; } /*clear方法,遍历table数组将每一个entry对象置为null,等待虚拟机将其回收*/ public void clear() { modCount++; Entry[] entrys = table; for (int i = 0; i < entrys.length; i++) entrys[i] = null; size = 0; /*将size置为0*/ } /*object代表的是value的值*/ public boolean containsValue(Object object) { if (object == null) return containsNullValue(); Entry[] entrys = table; /*用两个for循环来遍历,其实效率不高啦*/ for (int i = 0; i < entrys.length; i++) { /*防止有出现链表的情况,所以在每个table数组的位置在遍历一次,逐个对比*/ for (Entry entry = entrys[i]; entry != null; entry = entry.next) { if (object.equals(entry.value)) return true; /*找到则返回true*/ } } return false; } /*当传进来的value等于null时调用这个方法,原理和上面的方法一致*/ private boolean containsNullValue() { Entry[] entrys = table; for (int i = 0; i < entrys.length; i++) { for (Entry entry = entrys[i]; entry != null; entry = entry.next) { if (entry.value == null) return true; } } return false; } /*用来克隆的方法,此方法比较简单*/ public Object clone() { HashMap hashmap_38_ = null;/*新创建一个hashmap对象*/ try { hashmap_38_ = (HashMap) super.clone(); } catch (CloneNotSupportedException clonenotsupportedexception) { /* empty */ } hashmap_38_.table = new Entry[table.length];/*创建一个新的table*/ hashmap_38_.entrySet = null; hashmap_38_.modCount = 0; /*将它设为0是因为putAllForCreate(this)方法会在内部进行modCount++ */ hashmap_38_.size = 0; hashmap_38_.init(); hashmap_38_.putAllForCreate(this); return hashmap_38_; /最后返回此hashmap对象/ } /*此方法在指定的地方添加一个新的对象,指定的地方为 i_40_*/ void addEntry(int i, Object object, Object object_39_, int i_40_) { Entry entry = table[i_40_]; table[i_40_] = new Entry(i, object, object_39_, entry); /*这句代码将新加的对象加到table[i_40_]处*/ /*进行容量大小判定,如果因为多加一个对象而超出容量,则扩容*/ if (size++ >= threshold) resize(2 * table.length); } /*原理同上*/ void createEntry(int i, Object object, Object object_41_, int i_42_) { Entry entry = table[i_42_]; table[i_42_] = new Entry(i, object, object_41_, entry); size++; } Iterator newKeyIterator() { return new KeyIterator(null); } Iterator newValueIterator() { return new ValueIterator(null); } Iterator newEntryIterator() { return new EntryIterator(null); } public Set keySet() { Set set = keySet; return set != null ? set : (keySet = new KeySet(null)); } public Collection values() { Collection collection = values; return collection != null ? collection : (values = new Values(null)); } /*entrySet集合*/ public Set entrySet() { return entrySet0(); } private Set entrySet0() { Set set = entrySet; return set != null ? set : (entrySet = new EntrySet(null)); } /*下面两个方法我几乎没用过,建议去百度看看其他大神的解释,我这就不多说了*/ private void writeObject(ObjectOutputStream objectoutputstream) throws IOException { Iterator iterator = size > 0 ? entrySet0().iterator() : null; objectoutputstream.defaultWriteObject(); objectoutputstream.writeInt(table.length); objectoutputstream.writeInt(size); if (iterator != null) { while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); objectoutputstream.writeObject(entry.getKey()); objectoutputstream.writeObject(entry.getValue()); } } } private void readObject(ObjectInputStream objectinputstream) throws IOException, ClassNotFoundException { objectinputstream.defaultReadObject(); int i = objectinputstream.readInt(); table = new Entry[i]; init(); int i_43_ = objectinputstream.readInt(); for (int i_44_ = 0; i_44_ < i_43_; i_44_++) { Object object = objectinputstream.readObject(); Object object_45_ = objectinputstream.readObject(); putForCreate(object, object_45_); } } int capacity() { return table.length; } float loadFactor() { return loadFactor; }}
HashSet源码及分析 因为hashset实际上就是hashmap的封装,所以它内容很少,基本很多方法都是直接用hashmap里的方法,不过只是hashset里面的value值是不重复的而已
/* 可以看到,hashset继承了AbstractSet接口,实现了Set,Cloneable, Serializable接口*/public class HashSet extends AbstractSet implements Set, Cloneable, Serializable{/*serialVersionUID序列id,transient HashMap map 说一下transient 。transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。然而非transient型的变量是被包括进去的。我们也可以看到,Hashset里有以HashMap定义的map,可以说,HashSet实际上就是用HashMap来实现的*/ static final long serialVersionUID = -5024744406713321676L; private transient HashMap map; /*HashSet里的value就是PRESENT对象,*/ private static final Object PRESENT = new Object(); /*默认构造函数,创建出一个HashMap对象,以HashMap默认的16容量和0.75的负载因子创建*/ public HashSet() { map = new HashMap(); } /*传入collection集合对象来创建一个map对象,也是使用的是hashmap里的一个构造函数来创建map对象*/ public HashSet(Collection collection) { map = new HashMap(Math.max(((int) ((float) collection.size() / 0.75F) + 1), 16)); addAll(collection);/*addall() hashmap里的静态方法*/ } /*以下几个都是hashmap的构造函数,大家看看就知道什么意思了,后面的代码里会说*/ public HashSet(int i, float f) { map = new HashMap(i, f); } public HashSet(int i) { map = new HashMap(i); } HashSet(int i, float f, boolean bool) { map = new LinkedHashMap(i, f); } /*Iterator迭代器,用来迭代出keySet里的值*/ public Iterator iterator() { return map.keySet().iterator(); } /*map的大小*/ public int size() { return map.size(); } /*判断是否为空*/ public boolean isEmpty() { return map.isEmpty(); } /*由于hashset里面只存value,所以contains方法里直接调用map里的containsKey()方法就行了,因为其实hashmap里的key集合就是一个hashset,key的值是不会重复的*/ public boolean contains(Object object) { return map.containsKey(object); } /*add方法,调用map的put方法,上面hashmap里已经解释过了*/ public boolean add(Object object) { return map.put(object, PRESENT) == null; } /*和hashmap的remove方法原理一样的*/ public boolean remove(Object object) { return map.remove(object) == PRESENT; } /*和hashmap的clear的实现步骤是一样的*/ public void clear() { map.clear(); } /*基本上都是直接用的hashmap的clone方法*/ public Object clone() { HashSet hashset_0_; try { HashSet hashset_1_ = (HashSet) super.clone(); hashset_1_.map = (HashMap) map.clone(); hashset_0_ = hashset_1_; } catch (CloneNotSupportedException clonenotsupportedexception) { throw new InternalError(); } return hashset_0_; } private void writeObject(ObjectOutputStream objectoutputstream) throws IOException { objectoutputstream.defaultWriteObject(); objectoutputstream.writeInt(map.capacity()); objectoutputstream.writeFloat(map.loadFactor()); objectoutputstream.writeInt(map.size()); Iterator iterator = map.keySet().iterator(); while (iterator.hasNext()) objectoutputstream.writeObject(iterator.next()); } private void readObject(ObjectInputStream objectinputstream) throws IOException, ClassNotFoundException { objectinputstream.defaultReadObject(); int i = objectinputstream.readInt(); float f = objectinputstream.readFloat(); map = (this instanceof LinkedHashSet ? (HashMap) new LinkedHashMap(i, f) : new HashMap(i, f)); int i_2_ = objectinputstream.readInt(); for (int i_3_ = 0; i_3_ < i_2_; i_3_++) { Object object = objectinputstream.readObject(); map.put(object, PRESENT); } }}
分析完了hashmap和hashset的源码,我们来总结一下他们的遍历方式吧。
1:hashmap遍历的方式
第一种:
Map map = new HashMap();
Iterator iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
Object key = entry.getKey();
Object val = entry.getValue();
}
效率高,以后一定要使用此种方式!
第二种:
Map map = new HashMap();
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
Object key = iter.next();
Object val = map.get(key);
}
效率低,以后尽量少使用!
2:hashset的遍历方式
hashset遍历的方式很单一,就是直接使用迭代器来遍历
Set set = new HashSet(); //集合都可以用Iterator来遍历
Iterator it = set.iterator();
while (it.hasNext()) {
String str = it.next();
System.out.println(str);
}
hashmap和hashset的源码和分析就到这里了,第一次写博客,可能有很多地方写的不好,要是有写的不对的地方,欢迎前来指正!谢谢!
- 文章标题 【Java源码浅析】关于HashMap和HashSet的异同和源码分析
- java-HashMap和HashSet源码分析
- HashSet和HashMap源码实现分析
- Java HashSet和HashMap源码剖析
- Java HashSet和HashMap源码剖析
- Java HashSet和HashMap源码剖析
- Java HashSet和HashMap源码剖析
- HashMap和HashSet(深入HashMap源码分析HashMap元素的存储)
- HashMap和HashSet(深入HashMap源码分析HashMap元素的存储)
- HashMap HashSet源码分析
- java源码分析之HashSet和LinkedHashSet
- java HashSet HashMap(源码分析)
- 【Java源码分析】LinkedHashSet和HashSet源码分析
- Java 集合框架 HashSet 和 HashMap 源码剖析
- Java 集合框架-HashSet 和 HashMap 源码剖析
- HashTable 和 HashSet 的源码分析
- JDK中ArrayList、HashMap和HashSet的equals方法源码分析
- 从源码来理解HashMap和HashSet
- MVC模式 探索
- hdu 1392(凸包)
- top n with ties
- 【模板】【图论】最近公共祖先(LCA)
- 8.15 N
- 文章标题 【Java源码浅析】关于HashMap和HashSet的异同和源码分析
- C Primer Plus 第二章
- Spring Bean的自动装配,注入及后处理器
- A
- memcached安装
- FileChannel通道 NIO 读写
- 人生感悟文章(链接)
- dp--矩阵取数问题
- 配置mongodb遇到的坑