很多时候我们在讨论List与Set的异同点时都在说:

  1、List、Set都实现了Collection接口

  2、List是有序的,可以存储重复的元素,允许存入null

  3、Set是无序的,不允许存储重复的元素,只允许存入一个null

  4、List查询效率高,但插入删除效率低

  5、Set检索元素效率低、但删除插入效率高

  6、List可以通过索引操作元素,Set不能根据索引获取到元素

这里基于ArrayList/HashSet(jdk1.8)的角度进行分析两者的异同点:

一、从各自所继承的父类以及实现接口,可知两者的源头是一致的,都是从Collection接口延伸出来

二、创建ArrayList实例

不指定初始容量时,创建一个空的对象数组,与原有注释不一致,注释写着创建一个长度为10的数组,实际是在添加元素时进行判断处理的。还可以指定容量创建相应长度的数组、也可以传入一个集合来进行创建,此处就不再详细列出

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

由创建实例可知,ArrayList底层是由数组实现的,因是数组的方式实现,而数组实际是有序数据的集合,所以List也就相应是有序的,且也是能存入null。

三、创建HashSet实例

在不指定容量的情况下创建HashSet时,直接是去创建一个HashMap实例,用HashMap来实现HashSet的相关功能。可以指定容量和负载因子等进行创建,实际也是HashMap的其他构造方法

 /**
* 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<>();
}

由创建实例可知,底层实现为HashMap,既然是HashMap,按HashMap的规则,我们也就可知HashSet是无序的,因为HashMap的存储方式是先用key进行hash找到相应位置,然后再在该位置存储对应的key和value。HashSet不允许存储重复元素,是因为HashSet在添加元素时,是用该元素作为key,一个空的对象作为value进行存储的,也就相应的只能存储一个null

具体可见下图:

// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
/**
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element <tt>e</tt> to this set if
* this set contains no element <tt>e2</tt> such that
* <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
* If this set already contains the element, the call leaves the set
* unchanged and returns <tt>false</tt>.
*
* @param e element to be added to this set
* @return <tt>true</tt> if this set did not already contain the specified
* element
*/
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}

四、List查询效率高,但插入删除效率低

a、ArrayList是数组的方式实现,数组在内存中是连续且成块存储的,在查询时直接根据索引来获取数组相应值,所以查询效率会比较高

/**
* Returns the element at the specified position in this list.
*
* @param index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
rangeCheck(index); return elementData(index);
}

b、在做插入和删除操作时,如果直接添加一个元素,不指定索引时,直接添加到数组的末尾,也会比较快,如果需要按索引去添加时就需要对原有数组的相应后续元素进行复制移位再进行对该索引对应的位置进行赋值,删除同样,把该索引的后续元素复制前移一位,然后把最后一个索引置空待GC,因此插入和删除操作效率会相对较低

//直接添加元素,在数组的最后添加(在添加元素之前,先判断数组长度是否满足,如果第一次添加,则创建一个长度为10的数组,如果非第一次添加,则判断数组长度是否充足,如果不长度不够则创建一个长度为(oldCapacity + (oldCapacity >> 1))的新数组,
//并把旧舒服复制到新的数组中来)
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
} //先判断索引是否有效,再判断数组长度是否充足,不充足则参照上面流程添加新数组,再进行数组的复制移位
public void add(int index, E element) {
rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
} //如上面解释
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;
}

五、Set检索元素效率低、但删除插入效率高

HashSet没有get单个值得方法。在检索元素时,需要先获取map的所有数据,再进行遍历比对,所以效率会比ArrayList低。而在删除插入时,根据map的特性,只需要要对所插入的对象作为key进行hash找到相应位置,然后放入该元素即可,所以相对ArrayList的需要进行数组的复制移位来说效率会相对较高

//如上面解释,HashSet的remove实际也就是map的remove
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}

六、List可以通过索引操作元素,Set不能根据索引获取到元素

由上面分析可知,ArrayList是数组实现,存在索引可操作元素,而HashSet是HashMap实现,需要对元素进行hash找到位置再存储,不存在直接索引获取的方式

从源码的角度分析List与Set的区别的更多相关文章

  1. 从源码的角度分析ViewGruop的事件分发

    从源码的角度分析ViewGruop的事件分发. 首先我们来探讨一下,什么是ViewGroup?它和普通的View有什么区别? 顾名思义,ViewGroup就是一组View的集合,它包含很多的子View ...

  2. 第九节:从源码的角度分析MVC中的一些特性及其用法

    一. 前世今生 乍眼一看,该标题写的有点煽情,最近也是在不断反思,怎么能把博客写好,让人能读下去,通俗易懂,深入浅出. 接下来几个章节都是围绕框架本身提供特性展开,有MVC程序集提供的,也有其它程序集 ...

  3. 从Android源码的角度分析Binder机制

    欢迎访问我的个人博客,原文链接:http://wensibo.top/2017/07/03/Binder/ ,未经允许不得转载! 前言 大家好,好久不见,距离上篇文章已经有35天之久了,因为身体不舒服 ...

  4. [转]Android事件分发机制完全解析,带你从源码的角度彻底理解(上)

    Android事件分发机制 该篇文章出处:http://blog.csdn.net/guolin_blog/article/details/9097463 其实我一直准备写一篇关于Android事件分 ...

  5. 从源码的角度解析View的事件分发

    有好多朋友问过我各种问题,比如:onTouch和onTouchEvent有什么区别,又该如何使用?为什么给ListView引入了一个滑动菜单的功能,ListView就不能滚动了?为什么图片轮播器里的图 ...

  6. 【转】Android事件分发机制完全解析,带你从源码的角度彻底理解(下)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9153761 记得在前面的文章中,我带大家一起从源码的角度分析了Android中Vi ...

  7. 从源码的角度解析Mybatis的会话机制

    坐在我旁边的钟同学听说我精通Mybatis源码(我就想不通,是谁透漏了风声),就顺带问了我一个问题:在同一个方法中,Mybatis多次请求数据库,是否要创建多个SqlSession会话? 可能最近撸多 ...

  8. Android AsyncTask完全解析,带你从源码的角度彻底理解

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11711405 我们都知道,Android UI是线程不安全的,如果想要在子线程里进 ...

  9. 从源码的角度看Activity是如何启动的

    欢迎访问我的个人博客,原文链接:http://wensibo.top/2017/07/03/Binder/ ,未经允许不得转载! 大家好,今天想与大家一起分享的是Activity.我们平时接触的最多的 ...

随机推荐

  1. Go语言程序结构分析初探

    每一种编程语言都有自己的语法.结构以及自己的风格,这也是每种语言展现各自魅力及众不同的地方.Go也不例外,它简单而优雅,与此同时使用起来也很有趣.在本文中,我们将讨论以下几点: Go程序结构 如何运行 ...

  2. GNU μC/OS-II 在 S3C2440 上中断的实现

    上一篇文章介绍了S3c2440的中断体系结构,今天我们来分析一下GNU-uC/OS-II在S3c2440上中断的实现. 首先找到IRQ的中断的向量,位于 2440init.S : OK ,我们通过名字 ...

  3. js串口通信 调用MSCOMM32控件 链接电子秤(完整版实现方案)

    硬件环境:RS232转USB串口线*1 电子秤*1(本人采用G&G E600Y-C型号称重仪) 电子秤原装RS232数据线*1 计算机*1 软件环境:RS232转USB串口线驱动(这个可以在串 ...

  4. cannot import name 'Flask' from 'flask'

    今天发现了智障的真我. 刚入门flask,建了一个文件命名叫flask.py 在virtualenv的容器里运行该py文件,报错cannot import name 'Flask' from 'fla ...

  5. Mongodb 集群实战

    该实战过程完全跟着官网一步一步实现 ,官网教程:https://docs.mongodb.com/manual/tutorial/atlas-free-tier-setup/ 使用Mongo Shel ...

  6. activeX

    对外接口和classid在idl文件中,接口功能实现在ctrl类中实现

  7. 【Spring】7、拦截器HandlerInterceptor

    处理器拦截器简介 Spring Web MVC的处理器拦截器(如无特殊说明,下文所说的拦截器即处理器拦截器) 类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理.   常见 ...

  8. Why is 'x' in ('x',) faster than 'x' == 'x'?

    Question: >>> timeit.timeit("'x' in ('x',)") 0.04869917374131205 >>> tim ...

  9. 利用批处理文件删除系统托盘上的图标(适用于Windows各个版本)

    对于我这种强迫症患者来说,如果我已经删除了一些软件,但是系统托盘里面还有它,我会很难受.所以,没办法,必须想办法把它清除掉,还自己一片安宁!!!不知各位是否遇到过和我一样的问题,下面贴一段批处理文件的 ...

  10. WordPress 新版本中编辑器不好用, 使用原有编辑器

    将以下代码添加到当前主题的函数模板 functions.php 文件中即可. add_filter('use_block_editor_for_post', '__return_false'); re ...