前几期我们总结了有关于 Collection 的相关知识,这期来总结 关于Collection接口下的 存储有序元素可重复 List<E>接口 集合 和存储无序元素不可重复 Set<E> 接口 集合。
目录
5.ArrayList 和 LinkedList 和Vector的区别
一、interface List<E>
1.概念介绍:
1.1 简述:
在Collection中,List集合是有序的,用来表示线性表,可对其中每个元素的插入位置进行精确地控制,可以通过索引来访问元素,遍历元素。
1.2 官方相关:
public interface List<E> extends Collection<E>有序集合(也称为序列 )。 该界面的用户可以精确控制列表中每个元素的插入位置。 用户可以通过整数索引(列表中的位置)访问元素,并搜索列表中的元素。与集合不同,列表通常允许重复的元素。 更正式地,列表通常允许元素e1和e2成对使得e1.equals(e2) ,并且如果它们允许空元素,它们通常允许多个空元素。 有人可能希望实现一个禁止重复的列表,当用户尝试插入时会抛出运行时异常,但是我们预计这种使用是罕见的。(列表中元素允许重复,允许为空,限制较低)
public class Test01 { public static void main(String[] args) { List<Integer> integers = new ArrayList<>(); integers.add(null); integers.add(null); integers.add(null); integers.add(null); for (Integer integer : integers) { System.out.println(integer); } } } //输出结果: null null null null
该List接口放置额外的约定,超过在Collection指定接口上的iterator,add,remove,equals和hashCode方法合同。(就是有更多的方法)
List接口提供四种位置(索引)访问列表元素的方法。(就是可以通过索引下标进行增删改查)
所述List接口提供了一个特殊的迭代器,称为ListIterator,其允许元件插入和更换,并且除了该Iterator接口提供正常操作的双向访问。 提供了一种方法来获取从列表中的指定位置开始的列表迭代器
(public interface ListIterator<E> extends Iterator<E>,用于允许程序员沿任一方向遍历列表的列表的迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置)
- 其光标位置始终位于通过调用
previous()
返回的元素和通过调用next()
返回的元素next()
。 长度为n
的列表的迭代器具有n+1
可能的光标位置,如下图所示的^
(^
)所示:Element(0) Element(1) Element(2) ... Element(n-1) cursor positions: ^ ^ ^ ^ ^
(其实就是 正序 右侧多一个光标位置,逆序,左侧多一个光标位置,方便进行查询索引)(个人见解,不喜勿喷)
某些列表实现对它们可能包含的元素有限制。 例如,一些实现禁止空元素,有些实现对元素的类型有限制。 尝试添加不合格元素会引发未经检查的异常,通常为NullPointerException或ClassCastException 。 尝试查询不合格元素的存在可能会引发异常,或者可能只是返回false; 一些实现将展现出前者的行为,一些实现将展现出后者。 更一般来说,对于不完成不会导致将不合格元素插入到列表中的不合格元素的操作,可能会在执行选项时抛出异常或成功。 此异常在此接口的规范中标记为“可选”。(就是异常类型)
2. List接口下独有的方法
因为List接口是Collection接口的子接口,所以List接口需要重写Collection接口下的所有非私有方法,所以只介绍一下List独有的方法
增:
void add(int index,e)
在指定索引处插入一个元素;
boooleab addAll(int index,Collection<? extends E > e)
将一个集合插入到另外一个集合的指定位置;
删:
Collection 删除的时候,通过元素来删除 remove(Object obj)
E remove(int index);
通过索引下标来删除,并返回该元素;
改:
E set(int index,E e);
通过索引下标来修改集合元素,返回值是被修改的元素;
查:
E get(int index);
通过索引下标来查找集合元素,返回值是查找到的元素;
int indexOf(Object obj);
指定元素内容第一次出现的下标,返回值是元素下标;
int lastIndexOf(Object obj);
指定元素内容最后一次出现的下标,返回值是元素下标;
截取:
List<E> subList(int fromIndex,int toIndex);
截取集合中,指定元素下标(从左到右,取左不取右)的元素,返回值是一个新的集合
3. ArrayList
3.1 ArrayList 介绍
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable可调整大小的数组的实现List接口。 实现所有可选列表操作,并允许所有元素,包括null 。 除了实现List 接口之外,该类还提供了一些方法来操纵内部使用的存储列表的数组的大小。 (这个类是大致相当于Vector,不同之处在于它是不同步的)。
每个ArrayList实例都有一个容量 。 容量是用于存储列表中的元素的数组的大小。 它总是至少与列表大小一样大。 当元素添加到ArrayList时,其容量会自动增长。 没有规定增长政策的细节,除了添加元素具有不变的摊销时间成本。
3.2 ArrayList 特点
ArrayList 底层是数组,可以扩容。
默认的容量是10,超过10以后会自动扩容,扩容1.5倍
扩容:底层 Arrays.copeof(int index)
特征:查询快,增删慢
查询底层: 时间复杂度 O(1)
3.3 ArrayList构造方法
ArrayList() 构造一个初始容量为十的空列表。 |
ArrayList(Collection<? extends E> c) 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。 |
ArrayList(int initialCapacity) 构造具有指定初始容量的空列表。 |
ArrayList(Collection<? extends E> c)
有一个用法是 如果传入一个set集合 将其转为 list集合 就可以使用索引下标对其进行操作
3.4 遍历ArrayList集合
public static void main(String[] args) {
List<Integer> list1 = new ArrayList<>();
System.out.println(list1.size());
list1.add(11);
list1.add(22);
list1.add(44);
list1.add(33);
System.out.println(list1);
//for循环
for (int i = 0; i < list1.size(); i++) {
System.out.print(list1.get(i) + "\t");
}
System.out.println();
//增强for循环
for (Integer integer : list1) {
System.out.println(integer);
}
//迭代器
ListIterator<Integer> sli = list1.listIterator();
//正序
while (sli.hasNext()){
System.out.println(sli.next());
}
//逆序 逆序的前提是此时游标在最右侧(从左往右看集合)
while (sli.hasPrevious()){
System.out.println(sli.previous());
}
}
4.LinkedList
4.1 LinkedList简述
- 双链表实现了
List
和Deque
接口。 实现所有可选列表操作,并允许所有元素(包括null
)。所有的操作都能像双向列表一样预期。 索引到列表中的操作将从开始或结束遍历列表,以更接近指定的索引为准。
4.2 LinkedList特点
是List的实现类,底层是双向链表
特征:查询慢,增删快
底层:二分法查找
时间复杂度:增O(1) 删、改、查O(n)
4.3 LinkedList 构造方法
LinkedList() 构造一个空列表。 |
LinkedList(Collection<? extends E> c) 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。 |
4.4 LinkedList 独有方法
void |
addFirst(E e) 在该列表开头插入指定的元素。 |
void |
addLast(E e) 将指定的元素追加到此列表的末尾。 |
E |
get(int index) 返回此列表中指定位置的元素。 |
E |
getFirst() 返回此列表中的第一个元素。 |
E |
getLast() 返回此列表中的最后一个元素。 |
5.ArrayList 和 LinkedList 和Vector的区别
5.1ArrayList和Vector 的区别
ArrayList 和 Vector 底层是数组,但是Vector是线程安全的,所以效率低
5.2ArrayList与LinkedList的两者区别
数据结构不同,效率不同,自由性不同,主要控件开销不同
数据结构不同:ArrayList是Array(动态数组)的数据结构,LinkedList是Link(链表)双向链表的数据结构。
空间灵活性:ArrayList其实最好需要指定初始容量,LinkedList是比ArrayList灵活的,是根本不需要指定初始容量的
线程安全:ArrayList是线程不安全的,而LinkedList是线程安全的。
效率不同:
当随机访问List(get和set操作)时,ArrayList比LinkedList的效率更高,因为LinkedList是线性的数据存储方式,所以需要移动指针从前往后依次查找。ArrayList对于数据查询非常快,但是插入与删除元素比较慢;
当对数据进行增加和删除的操作(add和remove操作)时,LinkedList是恰好相反的,它的查询速度非常慢,但是插入与删除元素的速度非常快。
6.简单代码使用示例
/*
使用ArrayList集合,对其添加100个不同的元素:
1.使用add()方法将元素添加到ArrayList集合对象中;
2.调用集合的iterator()方法获得Iterator对象,并调用Iterator的hasNext()和next()方法,迭代的读取集合中的每个元素;
3.调用get()方法先后读取索引位置为50和102的元素,要求使用try-catch结构处理下标越界异常;
*/
public class Test {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list = randomList(list);
System.out.println("100个随机且不同的数:" + list);
//迭代器遍历
Iterator<Integer> randomNumList = list.listIterator();
while (randomNumList.hasNext()){
for (int i = 0; i < 10; i++) {
System.out.print(randomNumList.next() + "\t");
}
System.out.println();
}
//根据下标get元素
getIndexElement(list,50);
getIndexElement(list,102);
}
//randomList
public static List<Integer> randomList(List<Integer> list){
int count = 0;
while (count < 100){
Random random = new Random();
int num = random.nextInt(101);
if(!list.contains(num)){
list.add(num);
count++; //计数为100,就退出循环
}
}
return list;
}
//getIndexElement
public static void getIndexElement(List<Integer> list,int index){
try {
System.out.println("查找所在下标的元素为:" + list.get(index));
}catch (IndexOutOfBoundsException e){
System.out.println("异常类型" + e);
System.out.println("所读取下标越界了!!!");
}finally{
System.out.println("查找结束");
}
}
}