1.集合类

数组:可以存储对象,也可以存储基本数据类型,但是一次只能存储一种类型,且长度一定,不可改变。

集合:只能存储对象,长度可变,可以存储不同类型的对象。Java集合类主要有三种:set,list,map

其中,实现边框的是实现类,折线边框的是抽象类,点线边框的是接口

从图中可以看出,Collection接口是集合类(List,Set,Queue)的根接口,java中没有提供这个接口的直接实现类。有三个子接口List,Set,Queue,注意,Map不是collection的子接口。

Collection中的方法:

2.Collection中的List和Set接口

首先说一下List接口。 List里存放的对象是有序的,可重复的,可以为null的集合。List关注的是索引,拥有一系列和索引相关的方法,查询速度快。

List接口下主要的三个实现类:Arraylist,Linkedlist,Vector。

(1)ArrayList

  arraylist实现List接口,继承AbstractList。底层是数组实现,可以自增扩容。是非线程安全的,一般用于单线程环境中(与Vector最大的区别就是,V是线程安全的,所以A比V的性能相对要好些),在多线程中,可以选择Vector或者CopyOnWriteArrayList。Arraylist实现了Serializable接口,支持序列化,能够通过序列化传输;实现了RandomAccess接口(只是个标注接口,没有实际的方法),支持快速随机访问,主要变现为可以通过下标直接访问(因为Arraylist的底层是数组,可直接用数组下标来索引);实现了Cloneable接口,能被克隆。 Arraylist是基于动态数组实现的。

public class ArrayList<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable

  1)初始化

  Arraylist提供了三种初始化方法。

public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
} /**
* Constructs an empty list with an initial capacity of ten.//默认提供容量为10的数组。
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
} /**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class); //注意size是记录该list集合当前元素的数量,不是容量
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}

2)动态调整

无参构造函数默认的是空数组,为什么注释说是容量为10的数组。主要是ArrayList的add方法。add方法中调用了ensureCapacityInternal()方法,

 /**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}

从上述源码中可以看出,当elementData为空数组时,则使用Math.max(DEFAULT_CAPACITY, minCapacity)进行选择一个最大的,其中DEFAULT_CAPACITY为arraylist定义的静态常量=10;

private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
} private void ensureExplicitCapacity(int minCapacity) {
modCount++; // overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
} private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}

动态扩容最关键是grow方法 。通过源码中int newCapacity = oldCapacity + (oldCapacity >> 1);可得容量扩大为原来的1.5倍。

总之,ArrayList默认容量是10,如果初始化时一开始指定了容量,或者通过集合作为元素,则容量为指定的大小或参数集合的大小。每次扩容为原来的1.5倍,如果新增后超过这个容量,则容量为新增后所需的最小容量。如果增加1.5倍后的新容量超过限制的容量,则用所需的最小容量与限制的容量进行判断,超过则指定为Integer的最大值,否则指定为限制容量大小。然后通过数组的复制将原数据复制到一个更大(新的容量大小)的数组。

3)遍历方式

第一,随机访问,通过索引获取元素。ArrayList实现了randomaccess接口。

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

第二,for循环,foreach循环。

package Two;

import java.util.ArrayList;

public class one {

    public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList();
arrayList.add(1);
arrayList.add(3);
arrayList.add(9);
//for循环
for (int i = 0;i<arrayList.size();i++){
System.out.print(arrayList.get(i));
}
// foreach循环
for (Integer list:arrayList) {
System.out.print(list);
}
}
}

第三种:通过迭代器遍历

public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList();
arrayList.add(1);
arrayList.add(3);
arrayList.add(9);
Integer integer = null;
Iterator iterator = arrayList.iterator();
while (iterator.hasNext()){
integer = (Integer) iterator.next();
System.out.println(integer);
} }

上述三种遍历方式中,随机访问的效率最高,使用迭代器的效率最低。

总结:

  • ArrayList是List接口的一个可变大小的数组的实现

  • ArrayList的内部是使用一个Object对象数组来存储元素的

  • 初始化ArrayList的时候,可以指定初始化容量的大小,如果不指定,就会使用默认大小,为10

  • 当添加一个新元素的时候,首先会检查容量是否足够添加这个元素,如果够就直接添加,如果不够就进行扩容,扩容为原数组容量的1.5倍

  • 当删除一个元素的时候,会将数组右边的元素全部左移,添加一个元素时,右移。


2)LinkedList

public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, Serializable
LinkedList是一个继承AbstractSequentialList的双向链表。它可以被当作堆栈、队列或双端队列进行操作。
LinkedList实现了List接口,能对它进行队列操作。
LinkedList实现了Deque接口,即能将LinkedList当作双端队列使用
LinkedList实现了Cloneable接口,能克隆
LinkedList实现了java.io.Serializable接口,支持序列化,能通过序列化去传输
LinkedList是非同步的。
请注意,此实现不同步。 如果多个线程同时访问链接列表,并且至少有一个线程在结构上修改列表,则必须在外部进行同步。 (结构修改是添加或删除一个或多个元素的任何操作;仅设置元素的值不是结构修改。)这通常通过在自然封装列表的对象上进行同步来实现。 如果没有这样的对象存在,列表应该使用Collections.synchronizedList方法“包装”。 这最好在创建时完成,以防止意外的不同步访问列表:

  List list = Collections.synchronizedList(new LinkedList(...)); 

源码阅读有兴趣可自己去看

LinkedList特点:

  • 双向链表实现,没有固定容量,不需扩容
  • 元素是有序的,允许null值,输入输出顺序一致
  • 所有指定位置的操作都是从头开始遍历的
  • 需要更多的内存,LinkedList每个节点中需要存储前后节点的信息,占用空间更多
  • 查找效率低,插入删除效率高。

3)Vector

Vector非常类似ArrayList,但是Vector是同步的。由Vector创建的Iterator,虽然和ArrayList创建的Iterator是同一接口,但是,因为Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(例如,添加或删除了一些元素),这时调用Iterator的方法时将抛出ConcurrentModificationException,因此必须捕获该异常。

vector源码分析:https://www.cnblogs.com/skywang12345/p/3308833.html


3.List实现类的各种比较

1)Vector和ArrayList
相同点:两者都是基于存储元素的数组来实现的,它们会在内存中开辟块连续的空间来存储,由于数据存储是连续的,它们支持用序号(下标)来访问元素,但是插入和删除是要移动容器中的元素,所以执行较慢。两者都有一个初始化的容量的大小,为10;当里面存储的元素超过这个大小时,就会动态的进行扩容。Vector默认扩充为原来的2倍,ArrayList默认扩充为原来的1.5倍。
区别:二者最大的区别在与synchronization(同步)的使用。在ArrayList中没有一个方法是同步的,而在Vector中,绝大部分方法都是同步的。所以Vector是线程安全的,而ArrayList不是线程安全的。由于Vector提供同步,所以性能上较低于ArrayList。
2)ArrayList和LinkedList
  • ArrayList是实现了基于动态数组的数据结构,而LinkedList是基于双向链表的数据结构
  • 对于随机访问,ArrayList要优于LinkedList,因为LinkedList要移动指针
  • 对于插入和删除,LinkedList较占优势,ArrayList要移动数据。
  • ArrayList和LinkedList都是非线程安全的容器

在实际使用中,若对数据的主要操作为索引或只在集合的末端增加、删除元素,使用Arraylist和vector效率比较高;若对数据的操作主要为指定位置的插入或删除操作,使用Linkedlist效率比较高;当在多线程中使用容器时(即多个线程会同时访问该容器,),选用vector较为安全。

面试3——java集合类总结(List)的更多相关文章

  1. 面试3——java集合类面试题总结

    1.总结一下啊hashmap和hashtable的知识点? 1)关于hashmap的说法 HashMap实际上是一个“链表散列”的数据结构,在jdk1.8中添加了红黑树.HashMap底层结构是一个数 ...

  2. 面试3——java集合类总结(Map)

    1.概述: Java 中的map集合使用键值对(key-value)来保持数据,其中值(value)可以重复,键(key)必须唯一,但最多只能有一个key为空,它的主要实现类有HashMap.Hash ...

  3. BAT面试必备——Java 集合类

    本文首发于我的个人博客:尾尾部落 1. Iterator接口 Iterator接口,这是一个用于遍历集合中元素的接口,主要包含hashNext(),next(),remove()三种方法.它的一个子接 ...

  4. 面试3——java集合类总结(Set)

    Set 集合 和List一样,继承Collection接口,不同的是Set中不能包含重复的元素,无序,并且最多只能允许一个null值.Set常见的实现类有:HashSet.TreeSet和Linked ...

  5. Java集合类常见面试知识点总结

    微信公众号[Java技术江湖]一位阿里Java工程师的技术小站 Java集合类学习总结 这篇总结是基于之前博客内容的一个整理和回顾. 这里先简单地总结一下,更多详细内容请参考我的专栏:深入浅出Java ...

  6. JAVA集合类(大公司面试喜欢问的)

     分类: 核心JAVA(11)  版权声明:本文为博主原创文章,未经博主允许不得转载. 看了一些所谓大公司的Java面试问题,发现对于JAVA集合类的使用都比较看重似的,而自己在这方面还真的是所真甚少 ...

  7. Java集合类--温习笔记

    最近面试发现自己的知识框架有好多问题.明明脑子里知道这个知识点,流程原理也都明白,可就是说不好,不知道是自己表达技能没点,还是确实是自己基础有问题.不管了,再巩固下基础知识总是没错的,反正最近空闲时间 ...

  8. 大公司最喜欢问的Java集合类面试题

    看了一些所谓大公司的JAVA面试问题,发现对于JAVA集合类的使用都比较看重似的,而自己在这方面还真的是所真甚少,抽空也学习学习吧. java.util包中包含了一系列重要的集合类,而对于集合类,主要 ...

  9. 一招破解 Java 集合类面试题

    今日招式:Java集合类面试题 Java集合类绝对是我们的老朋友了,Java技术江湖里,谁人不知,谁人不晓,它的使用率非常高,使用难度却也不大,这也导致了很多人对它不屑一顾,殊不知其中却暗藏玄机,今天 ...

随机推荐

  1. Java并发编程(二)同步

    在多线程的应用中,两个或者两个以上的线程需要共享对同一个数据的存取.如果两个线程存取相同的对象,并且每一个线程都调用了修改该对象的方法,这种情况通常成为竞争条件.  竞争条件最容易理解的例子就是:比如 ...

  2. 对JS作用域和作用域链的理解

    理解好javascript的变量作用域和链式调用机制对用好变量起着关键的作用,下面我来谈谈这两个概念的理解. (1)链式调用机制 作用域链的定义:函数在调用参数时会从函数内部到函数外部逐个”搜索“参数 ...

  3. maven(六),外置maven运行环境配置

    外置maven eclipse内置的maven插件是固定版本,如果要用其他版本的maven,可以使用外置maven 下载地址: http://maven.apache.org/download.cgi ...

  4. JMeter—后置处理器(十)

    参考<全栈性能测试修炼宝典JMeter实战>第六章 JMeter 元件详解中第五节后置处理器后置处理器是用来处理采样器发送的请求后得到的响应数据 一.Debug PostProcessor ...

  5. python第七十六天--堡垒机完成

    堡垒机windows ,linux 都通过测试初始化说明: #进入根目录 1.初始化表结构 #python3 bin/start.py syncdb 2.创建堡垒机用户 #python3 bin/st ...

  6. 根据id来大量删除数据between

    id的范围来删除数据 比如要删除 110到220的id信息:delete id from 表名 where id between 110 and 220;

  7. 使用Jenkins+gitlab自动化构建时排除分支

    我们的目的是gitlab上的代码有变动时会自动向Jenkins发送web钩子请求,触发指定的动作: 但默认情况下,所有分支(如测试环境和预生产)的代码有变动时都会触发,此时可以在Jenkins的项目设 ...

  8. ELK-logstash-6.3.2部署

    Logstash 是一款强大的数据处理工具,它可以实现数据传输,格式处理,格式化输出,还有强大的插件功能,常用于日志处理. 1. logstash部署 [yun@mini04 software]$ p ...

  9. Alpha版本 - 测试报告

    Alpha版本 - 测试报告 总体测试计划 前端 模块 子模块 测试项 预期结果 测试工具 执行人 登录/注册模块 无网络 提示无网异常 robolectric 陈龙江 登录 输入用户名/密码为空,点 ...

  10. [Jenkins] 如何修改jenkins上的环境变量

    现象 当本地的环境变量发生变化时,在jenkins 构建时里面访问的环境变量仍是之前旧的(未更新的)导致构建出现错误,比如我以我所遇到的问题进行简单写下,下面例子中我是涉及到修改 PYTHONPATH ...