List
List接口继承Collection接口,被称为有序的Collection(序列)主要有如下三个特点
- 有序
- 有索引
- 可存在重复元素
常见的实现类:ArrayList,LinkedList
List接口中的抽象方法,有一部分和父接口Collection是一样的,而List接口自己独有的方法很好区分,就是方法中带有索引(int index),举例如下
package 集合;
import java.util.ArrayList;
import java.util.List;
public class ListDemo {
/**
* add(int index,E)
* 将元素E插入到列表的指定索引上,原来的元素后移
* 带有索引的操作,要防止越界问题!不可以超过列表的长度
* 当index为列表的长度时,插入到列表的末尾,index的取值范围在[0,list.size()]
*
* E remove(int index)
* 删除指定索引上的元素,同时返回被删除的元素
*
* E set(int index,E)
* 修改指定索引上的元素,同时返回被修改前的元素
* 注意和add方法的区别,index的取值范围在[0-list.size()-1]
* 因为是在指定的索引上进行修改,在index为列表长度时,该索引没有元素,会出现越界
*/
public static void function(){
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
System.out.println("初始list: "+list);
list.add(0,"one_insert");
System.out.println("list头添加元素: "+list);
list.add(list.size(),"last_insert");
System.out.println("list尾添加元素: "+list);
//get(int index) 返回指定索引的元素
System.out.println("get索引1上的元素:"+list.get(1));
String removed = list.remove(0);
System.out.println("删除一个元素后的list: "+list);
System.out.println("被删除的元素: "+removed);
String set_changed = list.set(list.size()-1,"last_insert_changed");
System.out.println("修改最后一个元素后的list: "+list);
System.out.println("被修改的元素: "+set_changed);
}
public static void main(String[] args) {
function();
}
}
//输出结果
初始list: [one, two, three]
list头添加元素: [one_insert, one, two, three]
list尾添加元素: [one_insert, one, two, three, last_insert]
get索引1上的元素:one
删除一个元素后的list: [one, two, three, last_insert]
被删除的元素: one_insert
修改最后一个元素后的list: [one, two, three, last_insert_changed]
被修改的元素: last_insert
list的遍历有三种方式:Iterator,for循环,增强for
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
Iterator<String> it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
for(String str:list){
System.out.println(str);
}
迭代器的并发修改异常 java.util.ConcurrentModificationException
:在遍历的过程中使用了集合的方法如add()等修改了集合的长度,如下
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
//对集合使用迭代器进行获取,获取时判断集合中是否存在 “two” 对象
//若存在,则添加一个元素 "ConcurrentModification"
Iterator<String> it = list.iterator();
while(it.hasNext()){
String str = it.next();
//判断字符串是否相等,使用equals()方法,不要使用==
if(str.equals("two")){
list.add("ConcurrentModification");
}
System.out.println(str);
}
面试时让你看代码写运行结果,千万不要很爽快的写出:one two three ConcurrentModification
Tips:在对集合进行遍历的过程中,使用集合的方法修改集合的长度,这是不允许的!!!
List集合数据存储的结构
List接口下有很多个集合,它们存储元素所采用的的结构方式是不同的,因此呈现各自的特点,方便我们在不同的环境下去选择不同的集合来使用,常见的数据存储结构有:堆栈,队列,数组,链表
堆栈
- 先进后出(子弹装弹,先压进去的子弹在下面,后压进去的子弹在上面,开枪时,后压进的子弹先弹出)
- 栈的入口和出口都是栈的顶端位置
- 进栈:存元素,即把元素存储到栈顶的位置,栈中已有的元素依次向栈底方向移动一个位置
- 出栈:取元素,取出栈顶的元素,栈中已有的元素依次向栈顶方向移动一个位置
队列
- 先进先出(过安检,排成一列,每个人依次检查,只有前面的人全部检查完毕后,才能排到当前的人进行检查)
- 队列的入口和出口各占一侧
数组
- 查找元素快,通过索引可以快速访问指定位置的元素
- 增删元素慢:指定索引位置增加元素(需要创建一个新数组,将指定新元素存储在指定索引位置,再把原数组元素根据索引,复制到新数组对应索引的位置)指定索引位置删除元素(需要创建一个新数组,把原数组元素根据索引,复制到新数组对应索引的位置,其中原数组中指定索引位置元素不复制到新数组中)
链表
- 多个节点之间通过地址连接(多个人手拉手,每个人使用自己的右手拉住下个人的左手,以此类推,多个人就连在一起了),节点由两个部分组成:数据域(存储的数值),指针域(存储的地址)
- 查找元素慢,想查找某个元素,需要通过连接的节点,依次向后查找指定元素
- 增删元素快,增加和删除元素(只要修改连接下个元素的地址即可)
ArrayList 是 List接口的大小可变的数组的实现,注意,实现不是同步的(线程不安全)
ArrayList集合存储数据的结构是数组结构,元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据和遍历数据,所以ArrayList是最常用的集合,但是在做程序开发时随意地使用ArrayList完成任何需求是不严谨的,不提倡
扫描二维码关注公众号,回复:
9468408 查看本文章
LinkedList是List接口的链表实现,实现同样不是同步的(线程不安全)
LinkedList集合存储数据的结构是链表结构,方便元素的添加与删除,因为实际开发中对一个集合元素的添加和删除经常涉及到首尾操作,所以LinkedList提供了大量首尾操作的方法,举例如下:
void addFirst(E e) //将指定元素插入此链表的开头
void addLast(E e) //将指定元素添加到此链表的末尾
E getFirst() //返回此链表的第一个元素
E getLast() //返回此链表的最后一个元素
E removeFirst() //删除并返回此链表的第一个元素
E removeLast() //删除并返回此链表的最后一个元素
E pop() //从此链表所表示的堆栈处弹出一个元素 相当于removeFirst()
void push(E e) //将元素推入此链表所表示的堆栈 相当于addFirst()
boolean isEmpty() //如果链表不包含元素,则返回 true
方法测试
package 集合;
import java.util.LinkedList;
/**
* 自身特点:链表底层实现,查询慢,增删快
*
* 使用子类的特有功能,不能多态调用,如 使用 removeFirst()方法,不能如下定义
* List<String> list = new LinkedList<String>(); //编译看左边,List接口并没有removeFirst()方法
*
*/
public class LinkedListDemo {
public static void main(String[] args) {
function();
}
public static void function(){
/**
* addFirst(E e) 添加到链表的开头
* addLast(E e) 添加到链表的末尾
* E getFirst() 获取到链表的第一个元素
* E getLast() 获取到链表的最后一个元素
* E removeFirst() 删除并返回第一元素
* E removeLast() 删除并返回最后一个元素
*/
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("one");
linkedList.add("two");
linkedList.addFirst("First");
linkedList.addLast("Last");
System.out.println("初始链表:"+linkedList);
//在get时要确保链表中存在元素,若是先执行clear情况链表,则get方法会产生java.util.NoSuchElementException异常
// !linkedList.isEmpty()等同于如下if条件判断
if(linkedList.size()!=0){ //避免NoSuchElement异常,可以先判断链表是否为空
System.out.println("链表的第一个元素:"+linkedList.getFirst());
System.out.println("链表的最后一个元素:"+linkedList.getLast());
}
String removed_First = linkedList.removeFirst();
String removed_Last = linkedList.removeLast();
System.out.println("被删除的第一个元素:"+removed_First+", 被删除的最后一个元素:"+removed_Last);
System.out.println("删除首尾元素后的链表:"+linkedList);
}
}
初始链表:[First, one, two, Last]
链表的第一个元素:First
链表的最后一个元素:Last
被删除的第一个元素:First, 被删除的最后一个元素:Last
删除首尾元素后的链表:[one, two]