从源码角度解析Java集合框架
2016-07-06 18:31
573 查看
1.ArrayList(允许重复的元素,允许null值,非线程同步的(Vector是同步的),其内部实现还是数组)
从源码中可以看出,contains方法是遍历object数组,通过object的equals方法来比较的
这回我们不用看代码,直接看代码上面的注释就可以知道ArrayList的clone方法是浅拷贝。(当然,对应的还有深拷贝,什么是浅拷贝,深拷贝,大家去百度吧,这里不作解释)
add方法不看源码,因为涉及到的方法很多,结论是,每次调用add方法的时候,系统会监测是否超过ArrayList的最大承受范围,如果超过了,就将ArrayList的容量扩大一倍,然后再进行元素的添加
remove方法
先检查要remove元素的下标是否越界,如果没有越界,就将该元素后面的所有元素往前移一位,最后将需要删除的那个元素赋值null,目的是通知垃圾回收机制去回收该对象
ArrayList中的Iterator,这相当于一个遍历器,能够依次访问到每个元素
ArrayList中的一些常见的方法都分析完了,其他的如果想自己分析,就查看JDK源码吧。与arraylist类似的还有LinkedList,内部是一个双向链表,学过数据结构的同学都知道,链表的插入元素和删除元素的时候比较方便,所以当数据量非常大的时候,用LinkedList更高效。
2.HashSet
开发中HashSet用的比较多,它不允许重复的元素,允许null值,而且是无序的,它内部是基于HashMap实现的。它有两个关键的因数,一个是capacity,另一个是load factor。官方建议不要将capacity设置太大或者将load factor设置太小。如果capacity设置太大,bucket就放不满,占用过多无效的内存空间;如果load factor设置过小,系统就会频繁得给bucket扩容,影响程序的运行效率。
从源码中可以看出,默认的capacity是16,load factor是0.75。具体意思就是当里面的元素个数达到16*0.75=12时,系统就会为HashSet扩容,扩容到当前的两倍
这几个方法内部都是通过HashMap来实现的,其他方法不赘述,其实都差不多
由于HashSet是无序的,所以没有办法通过正常的循环结构来遍历其中的数据,JDK给我们提供了Iterator接口,使用方法和ArrayList中的Iterator方法一样
与HashSet类似的还有LinkedHashSet,看名字就能猜得出来,内部实现原理是链表;TreeMap,可以用来排序的Set,初始化时候需要传一个Comparator参数
3.HashMap
HashMap允许空值,而Hashtable不允许空值
这里我们重点看put和get方法
get方法原理跟这个差不多,就不赘述了
HashMap中值得注意的一个知识点是,要判断两个元素是否相等,必须要同时满足hashcode和equals相同,只要有其中一个值不相同,就视为不同元素
与HashMap类似的一些集合类使用方法跟它差不多,所有就不多说了,可以自己查看JDK源码学习
学会看源码是一个程序员必备的技能!
public boolean contains(Object o) { return indexOf(o) >= 0; } public int indexOf(Object o) { if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } return -1; }
从源码中可以看出,contains方法是遍历object数组,通过object的equals方法来比较的
/** * Returns a shallow copy of this <tt>ArrayList</tt> instance. (The * elements themselves are not copied.) * * @return a clone of this <tt>ArrayList</tt> instance */ public Object clone() { try { @SuppressWarnings("unchecked") ArrayList<E> v = (ArrayList<E>) super.clone(); v.elementData = Arrays.copyOf(elementData, size); v.modCount = 0; return v; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(); } }
这回我们不用看代码,直接看代码上面的注释就可以知道ArrayList的clone方法是浅拷贝。(当然,对应的还有深拷贝,什么是浅拷贝,深拷贝,大家去百度吧,这里不作解释)
add方法不看源码,因为涉及到的方法很多,结论是,每次调用add方法的时候,系统会监测是否超过ArrayList的最大承受范围,如果超过了,就将ArrayList的容量扩大一倍,然后再进行元素的添加
remove方法
public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue; }
先检查要remove元素的下标是否越界,如果没有越界,就将该元素后面的所有元素往前移一位,最后将需要删除的那个元素赋值null,目的是通知垃圾回收机制去回收该对象
ArrayList中的Iterator,这相当于一个遍历器,能够依次访问到每个元素
ArrayList中的一些常见的方法都分析完了,其他的如果想自己分析,就查看JDK源码吧。与arraylist类似的还有LinkedList,内部是一个双向链表,学过数据结构的同学都知道,链表的插入元素和删除元素的时候比较方便,所以当数据量非常大的时候,用LinkedList更高效。
2.HashSet
开发中HashSet用的比较多,它不允许重复的元素,允许null值,而且是无序的,它内部是基于HashMap实现的。它有两个关键的因数,一个是capacity,另一个是load factor。官方建议不要将capacity设置太大或者将load factor设置太小。如果capacity设置太大,bucket就放不满,占用过多无效的内存空间;如果load factor设置过小,系统就会频繁得给bucket扩容,影响程序的运行效率。
/** * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has * default initial capacity (16) and load factor (0.75). */ public HashSet() { map = new HashMap<>(); }
从源码中可以看出,默认的capacity是16,load factor是0.75。具体意思就是当里面的元素个数达到16*0.75=12时,系统就会为HashSet扩容,扩容到当前的两倍
public int size() { return map.size(); } public boolean contains(Object o) { return map.containsKey(o); } public boolean add(E e) { return map.put(e, PRESENT)==null; } public boolean remove(Object o) { return map.remove(o)==PRESENT; } public void clear() { map.clear(); }
这几个方法内部都是通过HashMap来实现的,其他方法不赘述,其实都差不多
由于HashSet是无序的,所以没有办法通过正常的循环结构来遍历其中的数据,JDK给我们提供了Iterator接口,使用方法和ArrayList中的Iterator方法一样
与HashSet类似的还有LinkedHashSet,看名字就能猜得出来,内部实现原理是链表;TreeMap,可以用来排序的Set,初始化时候需要传一个Comparator参数
3.HashMap
HashMap允许空值,而Hashtable不允许空值
这里我们重点看put和get方法
public V put(K key, V value) { //如果HashMap内部的table是空的,就实例化一个table if (table == EMPTY_TABLE) { inflateTable(threshold); } //如果key为null,就调用putForNullKey() if (key == null) return putForNullKey(value); //如果key不为null,就找到key的hashcode所对应的地址,在该地址里面遍历所有的entry,看是否有相同的元素,相同则替换旧的value,不同就添加该元素 int hash = hash(key); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
get方法原理跟这个差不多,就不赘述了
HashMap中值得注意的一个知识点是,要判断两个元素是否相等,必须要同时满足hashcode和equals相同,只要有其中一个值不相同,就视为不同元素
与HashMap类似的一些集合类使用方法跟它差不多,所有就不多说了,可以自己查看JDK源码学习
学会看源码是一个程序员必备的技能!
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android Google Map获取地理位置信息的方法
- 从源码安装Mysql/Percona 5.5
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- Spark RDD API详解(一) Map和Reduce
- PropertyChangeListener简单理解
- Python中map()函数浅析
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序