最近在温习Java集合部分,花了三天时间读完了ArrayList与LinkedList以及Vector部分的源码。之前都是停留在简单使用ArrayList的API,读完源码看完不少文章后总算是对原理方面有了较清楚的认知。这部分文章整理基本都是这么一个套路:简单概括,分析源码增删改查,总结成文。

Java容器源码(精品):

https://blog.csdn.net/panweiwei1994/article/details/76555359#commentBox

https://juejin.im/post/5afbff9451882542877353dd

ArrayList动态扩容分析:

https://blog.csdn.net/zymx14/article/details/78324464

接下来整理了下关于List集合校招常见的面试题目:

1.ArrayList与Vector的区别

相同点:

都实现了List接口,允许元素重复和为null值。

底层都是数组,我们可以按位置索引出某个元素

不同点:

ArrayList是非同步的,在线程上不安全而Vector集合给它的每个API都套上了synchronized,所以Vector线程上是安全的。

在添加元素实现扩容的时候,ArrayList集合存储空间是增长为原来的1.5倍。而Vecto集合是存储空间增加为原来的2倍

PS:其实不考虑线程问题,他两没啥区别。

2.往ArrayList集合加入一万条数据,应该怎么提高效率?

ArrayList的构造方法有三种。当数据量比较大,这里又已经明确是一万条了,我们应该在初始化的时候就给它设置好容量。

不然使用无参构造器初始容量只有10,后面要扩容,扩容又比较伤性能,因为涉及到数组的复制,将原来的数组复制到新的存储区域中去。

PS:ArrayList动态扩容是一个重点一定要理解好,附上传送门:https://blog.csdn.net/zymx14/article/details/78324464

3.ArrayList插入删除一定很慢吗?

做过测试,ArrayList要是一直使用add方法在尾部插入的话,当数据量非常大的时候,其效率是要比LinkedList快的。删除也是。

但是要是在头部插入就要比LinkedList效率低不少。

可见测试分析报告:https://juejin.im/post/5c00987de51d451aa843b67b

四:ArrayList的遍历和LinkedList遍历性能比较如何?

Arraylist遍历性能要好,无论是全部遍历还是遍历某个元素都是这样。它底层使用数组,适合使用for循环按下标寻址。而LinkedList底层使用双向链表,虽说它在遍历的时候会采取折半查找的策略来提升速度但还是比不上ArrayList的速度。

五:ArrayList是如何扩容的\ArrayList是如何实现自动增加的?

如果是使用无参构造的话,初始容量是10,当超过了10个容量时,就需要扩容,每次扩容为之前的1.5倍。调用的是Arrays.copy(elementData,newCapacity)。所以扩容涉及到数组的复制和移动,我们应该避免扩容。在初始化的时候预估容量大小。

六:什么情况下你会使用ArrayList?什么时候你会选择LinkedList?

ArrayList底层使用数组,LinkedList底层使用双向链表。结合数据结构的特点可知,数组在空间上占用一片连续的内存空间,查询快。链表在增删操作只需要修改链表指针结点就可,增删快。

所以在查询使用较多时,选择ArrayList集合,增删使用较多时,选择LinkedList集合。

七:当传递ArrayList到某个方法中,或者某个方法返回ArrayList,什么时候要考虑安全隐患?如何修复安全违规这个问题呢?

把ArrayList当作参数传递到某个方法中去,涉及到一个浅拷贝深拷贝的问题。如果直接赋值给成员变量时,当成员变量发生改变时,其对应的传递过来的ArrayList也会改变

八:如何复制某个ArrayList到另一个ArrayList中去?

一般不直接用“=”赋值,这是将引用指向了同一片地址,一个修改了里面的内容另一个也会跟着变动。

一般采用如下方式: 

ArrayList A = new ArrayList();
//假设此时A集合已经有了数据。构造器法
ArrayList B = new ArrayList(A);
//clone法
ArrayList A = new ArrayList();
ArrayList B = (ArrayList) A.clone();
ArrayList A = new ArrayList();
//初始化时最好先预估容量大小
ArrayList B = new ArrayList();
B.addAll(A);

还可以调用Collections.copy()方法,参考博客:https://blog.csdn.net/tiantiandjava/article/details/51072173

九:在索引中ArrayList的增加或者删除某个对象的运行过程?效率很低吗?解释一下为什么?

查看源代码可以发现,当通过索引去增删元素的时候效率是比较低的,因为要频繁的进行数组的复制和移动,如果经常增删的话我们可以去考虑其他的集合。

通过索引增加过程:1.检查索引是否越界?2.检查容量是否足够?3调用System.arrayCopy(......)操作,效率较低

通过索引删除元素:1.检查索引是否越界?2.调用System.arrayCopy(....)操作

源代码截图如下:


以上是常见的面试题:接下来总结一下自己看源码所学到的

ArrayList:

1.ArrayList继承了AbstractList类,实现了List接口,RadomAccess,Clonable,Serialize接口。结合List接口特点可知它是有序的,可以存储重复值且可以为null。实现了RadomAccess接口在加上它底层采用数组实现,所以遍历速度快且遍历方式推荐使用for循环遍历下标而不用for-each或者iterator迭代器遍历。

2.使用默认无参构造时,初始容量分配为10.当进行增操作时,容量不够会进行扩容操作。

理清ArrayList增删改查操作:

add(E e):数组末尾进行增。

1.判断容量是否足够

2.size++

由此可见在末尾进行增操作时,是偶尔需要进行一次扩容操作,扩容时候会调用Arrays.copyOf(elementData, newCapacity);也与上文所说的在末尾插入效率并不比LinkedList低

public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}

public void add(int index, E element):按索引增。可知按索引增每次都要进行数组复制,所以效率低

1.判断索引是否越界 2.判断容量是否足够 3.size++

    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 boolean addAll(Collection<? extends E> c):增加一个集合。

1.先将所要增加的集合转为数组  2.判断容量  3:size++

   public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}

public E remove(int index):按索引值删除。可知每次都要进行数组复制,效率一样不高

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; // Let gc do its work return oldValue;
}

public boolean remove(Object o):按值删除  调用了fastRemove(index)方法,其内部也是要进行数组的复制,效率依然不高。

 public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}

LinkedList:

1.继承了AbstractSequentialList类,但AbstractSequentialList 只支持按次序访问,而不像 AbstractList 那样支持随机访问。这是LinkedList随机访问效率低的原因之一。

2.实现了List接口,说明有序,可以存储重复值,允许元素为null。实现了Deque接口,说明可以像操作栈和队列一样操作它。另外它还是可以被克隆和序列化的。

3.LinkedList底层是双向链表,链表在空间上是离散的,尽管Linked遍历时采用了折半查找,但效率依然较低。它的优势在于增删操作,尤其是在头结点。

ArrayList,LinkedList,Vector集合的认识的更多相关文章

  1. ArrayList LinkedList Vector

    ArrayList是基于数组实现的,没有容量的限制. 在删除元素的时候,并不会减少数组的容量大小,可以调用ArrayList的trimeToSize()来缩小数组的容量. ArrayList, Lin ...

  2. ArrayList, LinkedList, Vector - dudu:史上最详解

    ArrayList, LinkedList, Vector - dudu:史上最详解 我们来比较一下ArrayList, LinkedLIst和Vector它们之间的区别.BZ的JDK版本是1.7.0 ...

  3. List集合与Set集合(ArrayList,LinkedList,Vector,HashSet,LinkedHashSet,可变参数)

    List集合介绍及常用方法 import java.util.ArrayList; import java.util.Iterator; import java.util.List; /* java. ...

  4. 集合类源码(二)Collection之List(ArrayList, LinkedList, Vector)

    ArrayList 功能 完全命名 public class ArrayList<E> extends AbstractList<E> implements List<E ...

  5. java 中 ArrayList LinkedList Vector 三者的异同点

    1.ArrayList和Vector都是基于数组实现的,所以查询速度很快,增加和删除(非最后一个节点)速度慢: Vector是线程安全的,ArrayList不是. 2.LinkedList 是一个双向 ...

  6. ArrayList,LinkedList,vector的区别

    1,Vector.ArrayList都是以类似数组的形式存储在内存中,LinkedList则以链表的形式进行存储. 2.List中的元素有序.允许有重复的元素,Set中的元素无序.不允许有重复元素. ...

  7. ArrayList LinkedList Vector之间的区别

    List主要有ArrayList,LinkedList和vector三种实现.这三种都实现了List接口,使用方式也很相似,主要区别在于其实现方式的不同! 这三种数据结构中,ArrayList和Vec ...

  8. 集合框架的详解,List(ArrayList,LinkedList,Vector),Set(HashSet,TreeSet)-(14)

    集合详解: /* Collection |--List:元素是有序的,元素可以重复.因为该集合体系有索引. |--ArrayList:底层的数据结构使用的是数组结构.特点:查询速度很快.但是增删稍慢. ...

  9. hasSet,TreeSet,ArrayList,LinkedList,Vector,HashMap,HashTable,TreeMap利用Iterator进行输出

    基础类,没有重写hashCode()和equals()方法: package niukewang; import java.util.Objects; public class setClass { ...

随机推荐

  1. Linux 查看文件夹大小(排序)

    du -s * | sort -nr (-n是按数字大小排序,不能加上参数h)

  2. 【JS】JS以及CSS对页面的阻塞

    一.JS阻塞 所有的浏览器在下载JS文件的时候,会阻塞页面上的其他活动,包括其他资源的下载以及页面内容的呈现等等,只有当JS下载.解析.执行完,才会进行后面的 操作.在现代的浏览器中CSS资源和图片i ...

  3. L1、L2损失函数、Huber损失函数

    L1范数损失函数,也被称为最小绝对值偏差(LAD),最小绝对值误差(LAE) L2范数损失函数,也被称为最小平方误差(LSE) L2损失函数 L1损失函数 不是非常的鲁棒(robust) 鲁棒 稳定解 ...

  4. paper 139:qt超强绘图控件qwt - 安装及配置

    qwt是一个基于LGPL版权协议的开源项目, 可生成各种统计图.它为具有技术专业背景的程序提供GUI组件和一组实用类,其目标是以基于2D方式的窗体部件来显示数据, 数据源以数值,数组或一组浮点数等方式 ...

  5. jq实现跟随鼠标点击移动的下划线效果

    效果如下: 1.html代码: <div class="center-left-tap"> <a href="javascript:void (0)&q ...

  6. http协议和file协议的区别

    1.在本地直接使用浏览器打开  html文件 和 通过本地服务器打开  html文件  有什么区别呢.  https://segmentfault.com/q/1010000006554881/a-1 ...

  7. python基础-包和模块

    Python基础-包与模块 写在前面 如非特别说明,下文均基于Python3 摘要 为重用以及更好的维护代码,Python使用了模块与包:一个Python文件就是一个模块,包是组织模块的特殊目录(包含 ...

  8. 框架-.NET:.NET Core

    ylbtech-框架-.NET:.NET Core .NET Core是适用于 windows.linux 和 macos 操作系统的免费.开源托管的计算机软件框架,是微软开发的第一个官方版本,具有跨 ...

  9. Spring JDBC FOUND_ROWS 安全吗?

    在很多分页的程序中都这样写: SELECT COUNT(*) from `table` WHERE ......;  查出符合条件的记录总数 SELECT * FROM `table` WHERE . ...

  10. pandas 使用出现的问题汇总

    问题1:<bound method NDFrame.head of 刚开始还以为是自己的数据集有问题,怎么显示不对呢! 解决: 仔细观察,是自己给的输出有问题,data.head什么鬼??? 正 ...