很多时候我们在讨论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. 开发php的扩展模块(centos环境下)

    首先下载一份PHP的源码,并上传到centos服务器上 源码下载地址:https://github.com/php/php-src   然后在命令行进入到源码路径下的ext目录 然后创建扩展项目 [r ...

  2. 记一次升级Tomcat

    总述     JDK都要出12了,而我们项目使用的jdk却仍然还停留在JDK1.6.为了追寻技术的发展的脚步,我这边准备将项目升级到JDK1.8.而作为一个web项目,我们的容器使用的是Tomcat. ...

  3. windows7安装flask-mysqldb遇到的坑

    最近在windows环境上搭建flask使用环境,遇到过很多坑,这次就记录下安装flask-mysqldb所遇到的坑. 正常逻辑是使用pip install flask-mysqldb进行安装.但是会 ...

  4. 弱引用(WeakReference)

    在应用程序代码内实例化一个类或结构时,只要有代码引用它,就会形成强引用.这意味着垃圾回收器不会清理这样的对象使用的内存.但是如果当这个对象很大,并且不经常访问时,此时可以创建对象的弱引用,弱引用允许创 ...

  5. Intellij Idea乱码解决方案

    使用Intellij Idea经常遇到的三种乱码问题: 1.工程代码乱码 2.main方法运行,控制台乱码 3.tomcat运行,控制台乱码 解决方案: 1.工程代码乱码 Settings > ...

  6. API网关【gateway 】- 3

    最近在公司进行API网关重写,公司内采用serverMesh进行服务注册,调用,这里结合之前学习对API网关服务进行简单的总结与分析. 由于采用了大量的nginx相关的东西,所以在此记录一下: 在ng ...

  7. LVOOP设计模式在路上(二)-- 策略模式

    前言 最近工作还挺忙的,连着好些周都是单休了,今天休息在家就来写写关于策略模式的理解和labivew的实现. 正文 1.什么是策略模式 定义是这样描述的:它定义了算法家族,分别封装起来,让它们之间可以 ...

  8. Python全栈学习_day001作业

    Day1作业及默写 1.简述变量命名规范 1. 必须以字母.数字.下划线命名,且不能以数字开头 2. 不能是python的关键字 3. 不能以中文或者拼音作为变量名 4. 命名格式推荐以驼峰式或者下划 ...

  9. CSS图片两端对齐,自适应列表布局末行对齐修复实例页面

    写在前面 前端开发,图片两端对齐,是十分常见的,也是十分痛苦的,我试过好多方法,通过整理,认为下面还是比较靠谱的,在实践中大家可以试试,欢迎一起学习,一起进步 HTML代码 HTML代码非常简单,用的 ...

  10. MySQL and Sql Server:Getting metadata using sql script (SQL-92 standard)

    MySQL: use sakila; -- show fields from table_name; -- show keys from table_name; SELECT `REFERENCED_ ...