ArrayList

这里关于ArrayList本来都读了一遍源码,并且写了一些了,突然在原来的笔记里面发现了收藏的有相关博客,大致看了一下,这些就是我要写的(╹▽╹),而且估计我还写不到博主的水平,这里直接将收藏的博客列出来:

  1. 从源码角度彻底搞懂ArrayList

    这篇博客的重要内容包括:
    1. ArrayList使用的数据结构;
2. ArrayList的增删改查实现方式和时间复杂度分析;
3. ArrayList的自动扩容机制;
4. ArrayList的随机访问特性;
5. ArrayList与垃圾回收(因为对元素是强引用,在删除元素或移动元素时,被删除/被移动的元素原来的位置需要手动置为null)
6. ArrayList的并发修改,fail-fast机制
7. ArrayList的浅复制
8. ArrayList的序列化和反序列化
  1. ArrayList遍历方式以及效率比较

    这篇博客的关键内容:
    1. 探讨不同遍历方式(foreach iterator for循环)的遍历效率差原因;
2. ArrayList的随机访问特性,并且和顺序访问的LinkedList进行效率比较;
  1. 面试题:Java中ArrayList循环遍历并删除元素的陷阱

    除了上面的博文内容外,这里做些无关痛痒的补充....:

    /**
* ArrayList本身没有同步,如果需要在并发情况下使用,可以通过Collections.synchronizedList(List)进行包装,实现同步;
* @since 1.2
*/
// 这个继承了AbstractList,但是还是实现了List接口,想了半天,实现List接口这一点完全可以去掉.....,没有什么实际意义
// ArrayList实现了RandomAccess接口,证明其具有随机访问
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { // 将当前list中的数组大小缩减到size,以节约空间
public void trimToSize() {
modCount++;
int oldCapacity = elementData.length;
if (size < oldCapacity) {
elementData = Arrays.copyOf(elementData, size);
}
} ........ }

Vector

其实在jdk中,有一个与ArrayList实现非常相似,且在jdk1.0就已经存在的Vector类,我们来粗略看一下.

首先看一下Vector的类型定义

/**
* @since JDK1.0
*/
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable

Vector与ArrayList同样继承自AbstractList,实现相同的接口,那么其中必然有很多相同的方法,且仔细看,其中实现几乎全部都与ArrayList一致,这里不做多余分析

这里只对一些差异进行分析:

  1. 在jdk1.0,Vector的作者似乎很喜欢element这个单词:



    ArrayList中的size,在Vector中为elementCount,所有的增删改查方法都有以element开头或结尾的方法,如果去看其具体实现,和ArrayList中的相关增删改查方式没有什么区别;
  2. Vector的所有方法都加了锁(有些方法没有加锁,但是是被同步方法调用或内部调用同步方法实现),是线程安全的类;
  3. 除了添加的Iterator和ListIterator之外,Vector还有一个jdk1.0就存在的遍历方式:elments()返回一个Enumeration对象来遍历;
  4. Vector每次扩容时容量扩大的数量,通过一个成员变量:capacityIncrement来控制,如果capacityIncrement<=0,每次扩容后容量为原来的2倍;
  5. Vector的subList()方法返回的list是一个同步的list对象;
  6. 如果细看,Vector的序列化实现方式也和ArrayList不同,应该是为了兼容老代码,没有必要对此进行研究;

因为Vector每次操作都要获取锁,效率太低,因此如果没有线程安全的需求,一般推荐使用 ArrayList(其实如果有线程安全,也没有必要使用Vector,直接使用Collections.synchronizedList(List)包装出一个同步的list使用即可,将Vector踢进历史长河中)

既然讲了Vector这个被抛弃的类,那么也顺带说一下在Java中被公认为设计不良好的Stack类,从名字就可以看出来其预期是表示一个栈,但是我们看一下其类声明:

/**
* @since JDK1.0
*/
public
class Stack<E> extends Vector<E> { public Stack() {
} // 压栈
public E push(E item) {
addElement(item);
return item;
} // 弹栈
public synchronized E pop() {
E obj;
int len = size();
obj = peek();
removeElementAt(len - 1);
return obj;
} // 获取栈顶元素,但是不弹栈
public synchronized E peek() {
int len = size();
if (len == 0)
throw new EmptyStackException();
return elementAt(len - 1);
} // 获得指定对象o离栈顶的距离,如果o就是栈顶元素,则为1;如果栈中不存在元素o,返回-1;
public synchronized int search(Object o) {
int i = lastIndexOf(o); if (i >= 0) {
return size() - i;
}
return -1;
} /** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = 1224463164541339165L;
}

Stack之所以被认为设计不良好,是因为其继承了Vector类:

  1. 所有Vector中可被调用的方法,在相同情况下也可以在Stack中调用,这与Stack本身的定义就不符,Stack本身是一个LIFO的数据结构,只允许在一端压入,同一端取出(也即压栈和弹栈)的操作;
  2. Vector内部使用数组方式实现,有自动扩容机制,Stack继承Vector类,也就同样限制了Stack内部实现方式也是数组,也有动态扩容机制,这对Stack的实现没有必要(完全可以简单地使用链表实现);
  3. 可能是为了保持Vector线程安全的特点,Stack中的方法也全部为同步方法,这使得其效率低;

除此之外,Stack类还要注意pop()和peek()的区别:

  1. pop()是弹栈,及获取栈顶元素,并把栈顶元素删除;
  2. peek()只是获取栈顶元素,相当于查询,并不对栈进行其他操作;

在《Java编程思想》中,提供了另一中Stack实现方式:

// Making a stack from a LinkedList.

import java.util.LinkedList;

public class Stack<T>{

	private LinkedList<T> storage = new LinkedList<T>();

	public void push(T v){
storage.addFirst(v);
} public T peek(){
return storage.getFirst();
} public T pop(){
return storage.removeFirst();
} public boolean empty(){
return storage.isEmpty();
} public String toString(){
return storage.toString();
} }

这个栈的实现方式避免了上面说的Stack继承自Vector的问题;

Stack只含有一个LinkedList对象的引用,而不是继承LinkedList.

奇怪的是,jdk文档推荐使用Deque来代替Stack,如果查看LinkedList的类定义就知道其实现了Deque接口,但是这并不能避免上面的问题(只是非线程安全了,使效率有所提高);

而且jdk在明确了Stack之后,没有提供其他的Stack相关的类,《Java编程思想》中给出的解释"可能是因为Stack这个名字已经被占用",但是这并不能说通,因为完全可以弄出个"ArrayStack,LinkedStack"之类的名字;

Java容器解析系列(4) ArrayList Vector Stack 详解的更多相关文章

  1. Java容器解析系列(6) Queue Deque AbstractQueue 详解

    首先我们来看一下Queue接口: /** * @since 1.5 */ public interface Queue<E> extends Collection<E> { / ...

  2. java基础解析系列(十)---ArrayList和LinkedList源码及使用分析

    java基础解析系列(十)---ArrayList和LinkedList源码及使用分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder jav ...

  3. Java容器解析系列(0) 开篇

    最近刚好学习完成数据结构与算法相关内容: Data-Structures-and-Algorithm-Analysis 想结合Java中的容器类加深一下理解,因为之前对Java的容器类理解不是很深刻, ...

  4. Java容器解析系列(11) HashMap 详解

    本篇我们来介绍一个最常用的Map结构--HashMap 关于HashMap,关于其基本原理,网上对其进行讲解的博客非常多,且很多都写的比较好,所以.... 这里直接贴上地址: 关于hash算法: Ha ...

  5. Java容器解析系列(1) 迭代的进化——从Enumeration到Iterator

    在Java中,对于所有的Collection,都有一个特性,可以通过迭代器来遍历和删除其中的元素,因为Collection接口继承自Iterable接口. public interface Colle ...

  6. Java容器解析系列(7) ArrayDeque 详解

    ArrayDeque,从名字上就可以看出来,其是通过数组实现的双端队列,我们先来看其源码: /** 有自动扩容机制; 不是线程安全的; 不允许添加null; 作为栈使用时比java.util.Stac ...

  7. Java容器解析系列(13) WeakHashMap详解

    关于WeakHashMap其实没有太多可说的,其与HashMap大致相同,区别就在于: 对每个key的引用方式为弱引用; 关于java4种引用方式,参考java Reference 网上很多说 弱引用 ...

  8. Java容器解析系列(10) Map AbstractMap 详解

    前面介绍了List和Queue相关源码,这篇开始,我们先来学习一种java集合中的除Collection外的另一个分支------Map,这一分支的类图结构如下: 这里为什么不先介绍Set相关:因为很 ...

  9. Java容器解析系列(8) Comparable Comparator

    Comparable和Comparator接口是两个用于对对象进行大小比较的接口,在java集合相关类中,也被经常地使用到. 关于其使用,可以参考网络上的其他博客(没什么好说的);这里阐述关于这两个接 ...

随机推荐

  1. CentOS 7 开机延迟解决办法

    遇到这种情况 , 开机延迟 ,  可以用下面的办法来查看 , 寻找到问题的源头 , 来看看到的是怎么回事 [root@DaMoWang ~]# dmesg |grep udev #显示系统的启动信息 ...

  2. AD域与外部网站域名相同处理办法

    环境 域控:Windows Server 2008 r2 AD域:example.cn 问题:DNS可以正常解析外部域名(如www.baidu.com),但是无法解析mail.example.cn 原 ...

  3. Vue系列之 => 命名视图实现经典布局

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...

  4. 如何导出不带.svn的文件夹项目

    实际工作中有需要导出项目,却含有大量的.svn文件夹,有以下几种方式导出: 一.TortoiseSVN导出 项目文件夹,右键->TortoiseSVN->导出(Export),勾选“导出无 ...

  5. VXLAN

    网络协议栈 应用层:Telnet FTP HTTP SMTP... 传输层:TCP UDP 网络层:IP ICMP 物理链路层:ARP 以太网头(源目的MAC) | IP头(源目的IP) | TCP头 ...

  6. vscode菜单栏、工具栏不见了

    按alt可以出来菜单栏: 命令行切换出来 关键字 menu F1 or shift+ctrl+p 切换出命令行,然后输入menu 有个view:toggle Menu bar 的功能,没文档这个确实要 ...

  7. 一些sql优化原则

    1.我们在设计表的时候,尽量让字段拥有默认值,尽量不要让字段的值为null. 因为,在 where 子句中对字段进行 null 值判断(is null或is not null)将导致引擎放弃使用索引而 ...

  8. Docket 使用命令

    Docket 使用命令 查 # 查询当前可以下载的镜像 docker search httpd  |_ NAME:镜像仓库源的名称 |_ DESCRIPTION:镜像的描述 |_ OFFICIAL:是 ...

  9. Python 互斥锁

    互斥锁Mutex的使用 多个线程处理共享数据,数据会出现问题: 2.7之前每100指令切换一次GIL锁,线程就会sleep,线程会把前100条处理指令存放在CPU缓存内,切换GIL锁后放入另外一个线程 ...

  10. kernel: INFO: task sadc:14833 blocked for more than 120 seconds.

    早上一到,发现oracle连不上. 到主机上,发现只有oracleora11g一个进程,其他进程全没了. Nov 14 23:33:30 hs-test-10-20-30-15 kernel: INF ...