Java集合框架之List接口浅析
Java集合框架之List接口浅析
一、List综述:
毫无疑问List接口位于java.util包下,继承自 Collection接口
- 存储元素的特点:
有序可重复(有序:即存进去是什么顺序,取出来还是什么顺序,至于可重复相信大家都能理解)
存储元素对象:只存储引用数据类型(其实可以存储任何对象,基本数据类型会自动转为包装类存储),包括null,有时候我们也常把List称为序列
- 重要的实现类:ArrayList、LinkedList、Vector(我将在后续章节展开详细讨论,具体请关注我的博文)
二、List方法摘要:
boolean |
add(E e) 向列表的尾部添加指定的元素(可选操作)。 |
|
void |
add(int index, E element) 在列表的指定位置插入指定元素(可选操作)。 |
|
boolean |
|
|
boolean |
将指定 collection 中的所有元素都插入到列表中的指定位置(可选操作)。 |
|
void |
clear() 从列表中移除所有元素(可选操作)。 |
|
boolean |
contains(Object o) 如果列表包含指定的元素,则返回 true。 |
|
boolean |
containsAll(Collection<?> c) 如果列表包含指定 collection 的所有元素,则返回 true。 |
|
boolean |
equals(Object o) 比较指定的对象与列表是否相等。 |
|
E |
get(int index) 返回列表中指定位置的元素。 |
|
int |
hashCode() 返回列表的哈希码值。 |
|
int |
indexOf(Object o) 返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。 |
|
boolean |
isEmpty() 如果列表不包含元素,则返回 true。 |
|
Iterator<E> |
iterator() 返回按适当顺序在列表的元素上进行迭代的迭代器。 |
|
int |
lastIndexOf(Object o) 返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1。 |
|
ListIterator<E> |
listIterator() 返回此列表元素的列表迭代器(按适当顺序)。 |
|
ListIterator<E> |
listIterator(int index) 返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。 |
|
E |
remove(int index) 移除列表中指定位置的元素(可选操作)。 |
|
boolean |
remove(Object o) 从此列表中移除第一次出现的指定元素(如果存在)(可选操作)。 |
|
boolean |
removeAll(Collection<?> c) 从列表中移除指定 collection 中包含的其所有元素(可选操作)。 |
|
boolean |
retainAll(Collection<?> c) 仅在列表中保留指定 collection 中所包含的元素(可选操作)。 |
|
E |
set(int index, E element) 用指定元素替换列表中指定位置的元素(可选操作)。 |
|
int |
size() 返回列表中的元素数。 |
|
List<E> |
返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。 |
|
Object[] |
toArray() 返回按适当顺序包含列表中的所有元素的数组(从第一个元素到最后一个元素)。 |
|
|
toArray(T[] a) 返回按适当顺序(从第一个元素到最后一个元素)包含列表中所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。 |
三、相关扩展:
3.1List 与 Array 区别
List 在很多方面跟 Array 数组感觉很相似,尤其是 ArrayList,那 List 和数组究竟哪个更好呢?
相似之处:
都可以表示一组同类型的对象
都使用下标进行索引
不同之处:
数组可以存任何类型元素
List 不可以存基本数据类型,必须要包装
数组容量固定不可改变;List 容量可动态增长
数组效率高; List 由于要维护额外内容,效率相对低一些
容量固定时优先使用数组,容纳类型更多,更高效。
在容量不确定的情景下, List 更有优势,看下 ArrayList 和 LinkedList 如何实现容量动态增长:
ArrayList 的扩容机制:
public boolean add(E object) {
Object[] a = array; int s = size;
//当放满时,扩容
if (s == a.length) {
//MIN_CAPACITY_INCREMENT 为常量,12
Object[] newArray = new Object[s + (s < (MIN_CAPACITY_INCREMENT / 2) ? MIN_CAPACITY_INCREMENT : s >> 1)]; System.arraycopy(a, 0, newArray, 0, s);
array = a = newArray;
}
a[s] = object;
size = s + 1;
modCount++;
return true;
}
可以看到:
当 ArrayList 的元素个数小于 6 时,容量达到最大时,元素容量会扩增 12;
反之,增加 当前元素个数的一半。
LinkList的扩容机制:
public boolean add(E object) {
return addLastImpl(object);
}
private boolean addLastImpl(E object) {
Link<E> oldLast = voidLink.previous;
Link<E> newLink = new Link<E>(object, oldLast, voidLink);
voidLink.previous = newLink;
oldLast.next = newLink;
size++;
modCount++;
return true;
}
可以看到,没!有!扩容机制!
这是由于 LinedList 实际上是一个双向链表,不存在元素个数限制,使劲加就行了。
transient Link<E> voidLink;
private static final class Link<ET> {
ET data;
Link<ET> previous, next;
Link(ET o, Link<ET> p, Link<ET> n) {
data = o;
previous = p;
next = n;
}
}
3.2List 与 Array 之间的转换
在 List 中有两个转换成 数组 的方法:
Object[] toArray()
返回一个包含 List 中所有元素的数组;
T[] toArray(T[] array)
作用同上,不同的是当 参数 array 的长度比 List 的元素大时,会使用参数 array 保存 List 中的元素;否则会创建一个新的数组存放 List 中的所有元素;
ArrayList 中的实现:
public Object[] toArray() {
int s = size;
Object[] result = new Object[s];
//这里的 array 就是 ArrayList 的底层实现,直接拷贝
//System.arraycopy 是底层方法,效率很高
System.arraycopy(array, 0, result, 0, s);
return result;
}
public <T> T[] toArray(T[] contents) {
int s = size;
//先判断参数能不能放下这么多元素
if (contents.length < s) {
//放不下就创建个新数组
@SuppressWarnings("unchecked")
T[] newArray
= (T[]) Array.newInstance(contents.getClass().getComponentType(), s);
contents = newArray;
}
System.arraycopy(this.array, 0, contents, 0, s);
if (contents.length > s) {
contents[s] = null;
}
return contents;
}
LinkedList 的实现:
public Object[] toArray() {
int index = 0;
Object[] contents = new Object[size];
Link<E> link = voidLink.next;
while (link != voidLink) {
//挨个赋值,效率不如 ArrayList
contents[index++] = link.data;
link = link.next;
}
return contents;
}
@Override
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] contents) {
int index = 0;
if (size > contents.length) {
Class<?> ct = contents.getClass().getComponentType();
contents = (T[]) Array.newInstance(ct, size);
}
Link<E> link = voidLink.next;
while (link != voidLink) {
//还是比 ArrayList 慢
contents[index++] = (T) link.data;
link = link.next;
}
if (index < contents.length) {
contents[index] = null;
}
return contents;
}
数组工具类 Arrays 提供了数组转成 List 的方法 asList :
@SafeVarargs
public static <T> List<T> asList(T... array) {
return new ArrayList<T>(array);
}
使用的是 Arrays 内部创建的 ArrayList 的转换构造函数:
private final E[] a;
ArrayList(E[] storage) {
if (storage == null) {
throw new NullPointerException("storage == null");
}
//直接复制
a = storage;
}
3.3迭代器 Iterator, ListIterator
List 继承了 Collection 的 iterator() 方法,可以获取 Iterator,使用它可以进行向后遍历。
在此基础上,List 还可以通过 listIterator(), listIterator(int location) 方法(后者指定了游标的位置)获取更强大的迭代器 ListIterator。
使用 ListIterator 可以对 List 进行向前、向后双向遍历,同时还允许进行 add, set, remove 等操作。
List 的实现类中许多方法都使用了 ListIterator,比如 List.indexOf() 方法的一种实现:
public int indexOf(E e) {
for (ListIterator<E> it = listIterator(); it.hasNext(); )
if (e == null ? it.next() == null : e.equals(it.next()))
return it.previousIndex();
// Element not found
return -1;
}
ListIterator 提供了 add, set, remove 操作,他们都是对迭代器刚通过 next(), previous()方法迭代的元素进行操作。下面这个栗子中,List 通过结合 ListIterator 使用,可以实现一个多态的方法,对所有 List 的实现类都适用:
public static <E> void replace(List<E> list, E val, E newVal) {
for (ListIterator<E> it = list.listIterator(); it.hasNext(); )
if (val == null ? it.next() == null : val.equals(it.next()))
it.set(newVal);
}
参考:http://blog.csdn.net/u011240877/article/details/52802849
Java集合框架之List接口浅析的更多相关文章
- Java集合框架之Map接口浅析
Java集合框架之Map接口浅析 一.Map接口综述: 1.1java.util.Map<k, v>简介 位于java.util包下的Map接口,是Java集合框架的重要成员,它是和Col ...
- Java集合框架之Set接口浅析
Java集合框架之Set接口浅析 一.java.util.Set接口综述: 这里只对Set接口做一简单综述,其具体实现类的分析,朋友们可关注我后续的博文 1.1Set接口简介 java.util.se ...
- Java集合框架之Collection接口
Java是一门面向对象的语言,那么我们写程序的时候最经常操作的便是对象了,为此,Java提供了一些专门用来处理对象的类库,这些类库的集合我们称之为集合框架.Java集合工具包位于Java.util包下 ...
- java 集合框架(二)Iterable接口
Iterable接口是java 集合框架的顶级接口,实现此接口使集合对象可以通过迭代器遍历自身元素,我们可以看下它的成员方法 修饰符和返回值 方法名 描述 Iterator<T> iter ...
- Java集合框架之四大接口、常用实现类
Java集合框架 <Java集合框架的四大接口> Collection:存储无序的.不唯一的数据:其下有List和Set两大接口. List:存储有序的.不唯一的数据: Set:存储无序的 ...
- Java集合框架中Map接口的使用
在我们常用的Java集合框架接口中,除了前面说过的Collection接口以及他的根接口List接口和Set接口的使用,Map接口也是一个经常使用的接口,和Collection接口不同,Map接口并不 ...
- Java集合框架中List接口的简单使用
Java集合框架可以简单的理解为一种放置对象的容器,和数学中的集合概念类似,Java中的集合可以存放一系列对象的引用,也可以看做是数组的提升,Java集合类是一种工具类,只有相同类型的对象引用才可以放 ...
- Java集合框架的基础接口有哪些?
Collection为集合层级的根接口.一个集合代表一组对象,这些对象即为它的元素.Java平台不提供这个接口任何直接的实现. Set是一个不能包含重复元素的集合.这个接口对数学集合抽象进行建模,被用 ...
- java集合框架部分相关接口与类的介绍
集合基础 接口 Iterable //Implementing this interface allows an object to be the target of the "for-ea ...
随机推荐
- linux初学者-常用基本命令篇
linux系统中有着许许多多的命令,并且软件也有可能自带命令,要想全部了解这些命令是很困难的,但是有一些基本命令是在平时的学习工作中应用的很广泛的.以下简要介绍几种linux系统中的常用命令. 1.m ...
- 快速安装k8s,版本为1.13.8
利用rpm快速部署k8s #!/bin/bash #快速安装k8s #by love19791126 107420988@qq.com pwd=$(pwd) masteripaddr=#(ip a s ...
- Android Studio 蓝牙开发实例——基于Android 6.0
因项目需要做一个Android 的蓝牙app来通过手机蓝牙传输数据以及控制飞行器,在此,我对这段时间里写的蓝牙app的代码进行知识梳理和出现错误的总结. 该应用的Compile Sdk Version ...
- GitHub 用户排行榜
排行榜预览网址:Github | Githack | UNPKG | Gitee Github 中国用户排名,全球仓库 Star 最多排名,通过 Github API v3 来生成页面数据,排行榜预览 ...
- 201312-2ISBN号码
问题描述 每一本正式出版的图书都有一个ISBN号码与之对应,ISBN码包括9位数字.1位识别码和3位分隔符,其规定格式如“x-xxx-xxxxx-x”,其中符号“-”是分隔符(键盘上的减号),最后一位 ...
- SpringBoot:Web开发
西部开源-秦疆老师:基于SpringBoot 2.1.6 的博客教程 , 基于atguigu 1.5.x 视频优化 秦老师交流Q群号: 664386224 未授权禁止转载!编辑不易 , 转发请注明出处 ...
- Maven多模块项目打包前的一些注意事项(打包失败)
一. 最近在打包Maven项目时遇到了点问题,这个项目是Maven多模块项目,结构如下: projectParent├── xxxx-basic├── xxxx-web1├── xxxx-collec ...
- Opengl_入门学习分享和记录_番外篇00(MacOS上如何给Xcode 适配openGL)
现在前面的废话:哇这次没有鸽太久,突然想起来还没有介绍如何适配opengl的衍生库.今天一并介绍下,同样看时间允不允许,让我再把之前学到的一些东西再次总结一遍. 正文开始: 首先大家要知道我们的Ope ...
- eclipse项目导入idea jdk版本不一致😵
在导入eclipse项目到idea过程中遇到 Imported project refers to unkonwn jdks JavaSE-1.8 解决方法: file --> Project ...
- flask项目部署到云服务器+域名绑定
一.效果演示 首页展示 播放页面 该项目部署只为学习,所以用的服务器是腾讯云服务器10元/月,域名也是在腾讯云买的.com 55元/年 因为本人比较穷 哈哈