从源码的角度分析List与Set的区别
很多时候我们在讨论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 ? e2==null : 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的区别的更多相关文章
- 从源码的角度分析ViewGruop的事件分发
从源码的角度分析ViewGruop的事件分发. 首先我们来探讨一下,什么是ViewGroup?它和普通的View有什么区别? 顾名思义,ViewGroup就是一组View的集合,它包含很多的子View ...
- 第九节:从源码的角度分析MVC中的一些特性及其用法
一. 前世今生 乍眼一看,该标题写的有点煽情,最近也是在不断反思,怎么能把博客写好,让人能读下去,通俗易懂,深入浅出. 接下来几个章节都是围绕框架本身提供特性展开,有MVC程序集提供的,也有其它程序集 ...
- 从Android源码的角度分析Binder机制
欢迎访问我的个人博客,原文链接:http://wensibo.top/2017/07/03/Binder/ ,未经允许不得转载! 前言 大家好,好久不见,距离上篇文章已经有35天之久了,因为身体不舒服 ...
- [转]Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
Android事件分发机制 该篇文章出处:http://blog.csdn.net/guolin_blog/article/details/9097463 其实我一直准备写一篇关于Android事件分 ...
- 从源码的角度解析View的事件分发
有好多朋友问过我各种问题,比如:onTouch和onTouchEvent有什么区别,又该如何使用?为什么给ListView引入了一个滑动菜单的功能,ListView就不能滚动了?为什么图片轮播器里的图 ...
- 【转】Android事件分发机制完全解析,带你从源码的角度彻底理解(下)
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9153761 记得在前面的文章中,我带大家一起从源码的角度分析了Android中Vi ...
- 从源码的角度解析Mybatis的会话机制
坐在我旁边的钟同学听说我精通Mybatis源码(我就想不通,是谁透漏了风声),就顺带问了我一个问题:在同一个方法中,Mybatis多次请求数据库,是否要创建多个SqlSession会话? 可能最近撸多 ...
- Android AsyncTask完全解析,带你从源码的角度彻底理解
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11711405 我们都知道,Android UI是线程不安全的,如果想要在子线程里进 ...
- 从源码的角度看Activity是如何启动的
欢迎访问我的个人博客,原文链接:http://wensibo.top/2017/07/03/Binder/ ,未经允许不得转载! 大家好,今天想与大家一起分享的是Activity.我们平时接触的最多的 ...
随机推荐
- .Net Core中使用Quartz.Net
一.介绍 Quartz.Net是根据Java的Quartz用C#改写而来,最新的版本是3.0.6,源码在https://github.com/quartznet/quartznet.主要作用是做一些周 ...
- dom操作------获取长/宽/距离等值的若干方法
1.offsetLeft:获取元素边框以外至文档顶的距离:若其祖先元素有定位属性position则返回值为元素到该定位元素的距离,不包括祖先元素的三宽(padding,border,margin),且 ...
- Django学习(6)配置静态文件
本文将详细讲述如何在Django中配置静态文件,如图片(images),JavaScript,CSS等. 我们将要实现的网页如下: 当按下按钮"Change Text"时, ...
- PowerDesigner V16.5 安装教程以及汉化(数据库建模)
一.power designer是什么以及是干什么的? power designer是能进行数据库设计的强大的软件,是一款开发人员常用的数据库建模工具.分别从概念数据模型(Conceptual Dat ...
- C#7.2——编写安全高效的C#代码
原文地址:https://docs.microsoft.com/zh-cn/dotnet/csharp/write-safe-efficient-code?view=netcore-2.1 值类型的优 ...
- 使用Java打印字符串表格(中英文内容不乱)
最近在学习使用java来编写cli应用,但是在信息展示上碰到了难题.原因是没有很好工具来展示一个由字符串组成的表格.在git上搜到阿里巴巴有一个叫做 text-ui 的开源项目可以用,但是这个工具在制 ...
- 聊聊大麦网UWP版的首页顶部图片联动效果的实现方法
随着Windows10的发布,国内已经有越来越多的厂商上架了自家的通用应用程序客户端,比如QQ.微博.大麦等.所实话,他们设计的确实很好,很符合Windows10 的设计风格和产品理念,而对于开发者而 ...
- 小程序webview应用实践
原文:小程序webview实践 作者:张所勇(转转开放业务部前端负责人) 公众号:大转转FE Fundebug经授权转载,版权归原作者所有. 大家好,我是转转开放业务部前端负责人张所勇,今天主要来跟大 ...
- Django Rest framework 之 版本
RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...
- Installing Fonts programatically C#
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...