Java集合Collection接口之List子接口

List接口介绍

List接口是有序的collection(也称为序列,这个有序不是指的自然顺序,而是指添加进集合中的顺序与元素出来的顺序一致),用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。

主要的实现类有如下三个: 
ArrayList :底层是维护了一个Objecy数组实现的,特点:查询速度快,增删慢; 
LinkedList:底层是使用了链表数据结构实现的,特点:查询速度慢,增删块; 
Vector:底层维护了一个Object的数组实现的,实现与ArratList是一样的,但是Vector是线程安全的,同步的,操作效率低

实现方法

除了Collection接口实现的一些方法外,List接口有一些特有的方法,可以使用索引index快速操作,

  • 1:增加 
    void add(int index, E element) 指定位置添加元素 
    boolean addAll(int index, Collection c) 指定位置添加集合
  • 2:删除 
    E remove(int index) 删除指定位置元素
  • 3:修改 
    E set(int index, E element) 返回的是需要替换的集合中的元素
  • 4:查找: 
    E get(int index) 注意: IndexOutOfBoundsException 
    int indexOf(Object o) // 找不到返回-1 
    lastIndexOf(Object o)
  • 5:求子集合 
    List subList(int fromIndex, int toIndex) // 不包含toIndex
  • 6.迭代器 
    listIterator(int index) 
    List接口还提供了特殊的迭代器,称为ListIterator,除了允许Iterator接口提供的正常操作外,该迭代器还允许元素的差入和替换,以及双向访问,还提供了一个方法来获取从列表中指定位置开始的列表迭代器。 
    ListIterator迭代器特有方法: 
    hasPrevious() 判断是否存在上一个元素 
    previous:指针先向上移动一个单位,然后取出当前指向的元素 
    next():先取出当前指向的元素,然后指针向下移动一个单位 
    set(E e) :用指定元素替换next或previous返回的最后一个元素

遍历集合的方法

使用三种方法遍历集合的元素:

  • 1.使用get方法遍历
  • 2.使用迭代器正序遍历
  • 3.使用迭代器逆序遍历
//get方法遍历
for(int i = 0 ; i<list.size() ; i++){
System.out.print(list.get(i)+",");
}
//使用迭代器正序遍历
ListIterator it = list.listIterator(); //获取到迭代器
while(it.hasNext()){
System.out.print(it.next()+",");
}
 
//使用迭代器逆序遍历
while(it.hasPrevious()){
System.out.print(it.previous()+",");
}

注意: 
在使用迭代器迭代元素的过程中,不允许使用集合对象改变集合中的元素个数,若需要添加或删除只能使用迭代器的方法进行操作;若使用了集合对象改变,则会报ConcurrentModificationException异常。

实现类ArrayList使用

ArrayList实现类是类似于一个可变数组,长度可动态变化,允许包含null元素。此实现类不是同步的,若有多个线程同时访问一个ArrayList实例,而其中有一个线程从结构上修改了列表,那么它必须保持外部同步。(结构上的修改是指任何添加或删除一个或多个元素的操作,或者显式调整底层数组的大小,仅仅设置元素的值不是结构上的修改) 
ArrayList实现类的定义源码如下:

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
private transient Object[] elementData; //存储ArrayList内的元素,transient 关键字关闭序列化
private int size; //表示ArrayList内的元素个数
 
public ArrayList(int initialCapacity) { //构造一个具有指定初识容量的列表
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
public ArrayList() {
this(10);
}
public ArrayList(Collection<? extends E> c) { //构造一个具有指定collection的元素的列表
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}

ArrayList类继承了AbstractList(此类提供了List接口的主要实现),实现了List接口;
    RandomAccess是一个标记接口,用来表明其支持快速(通常是固定时间)随机访问(在这里的快速随机访问我的理解就是可以通过下标直接访问数组,已达到快速访问); 
    实现Cloneable接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制; 
    实现java.io.Serializable接口,这意味着ArrayList支持序列化,能通过序列化去传输,所谓的序列化就是将实现了Serializable接口的对象转换成一个字节序列,并能够在以后将这个字节序列完全恢复为原来的对象,可以通过网络进行,序列化机制能自动弥补不同操作系统之间的差异。(对于序列化的理解,参看https://my.oschina.net/u/1382972/blog/170148 ) 
    transient 关键字:若是实现了Serializable接口进行序列化功能,那么所有序列化操作都会自动进行,对于这些序列化处理的信息可以通过读取文件或者拦截网络传输的方式访问,因而为了保护信息安全(比如密码信息)或者有某个特定的子对象不想被Java序列化机制自动保存,就可以使用transient关键字关闭序列化。
如上源码可知ArrayList底层是维护了一个Object数组实现的,有三个默认构造函数,使用无参构造函数时,Object数组默认容量是10,当长度不够时,自动增长0.5倍,查询速度快。对于增删操作,因为牵扯到元素的拷贝(增加时,会申请一个更大的数组,将原有数组的元素拷贝至新的数组),速度慢。 
示例

/*
* 思路:创建一个新的集合,将旧集合中的元素一次复制到新集合,复制的前提是新集合中不存在该元素,就可以删除重复的
*/
import java.util.ArrayList;
import java.util.Iterator;
 
class Book{
int id;
String name;// 名字
 
public Book(int id, String name) {
this.id = id;
this.name = name;
}
 
@Override
public String toString() {
return "{ 书号:"+ this.id+" 书名:"+ this.name+" }";
}
 
@Override
public boolean equals(Object obj) {
Book book =(Book)obj;
return this.id==book.id;
}
}
 
// 需求: 编写一个函数清除集合中重复元素。 如果书号是一样就视为重复元素。 要求: 遍历集合元素的时候必须使用迭代器。 java编程思想和java探秘书号一样,第二个java探秘会被清除
public class Test {
public static void main(String[] args) {
ArrayList list= new ArrayList();
list.add(new Book(110,"java编程思想"));
list.add(new Book(220,"java核心技术"));
list.add(new Book(330,"JVM虚拟机"));
list.add(new Book(110,"java探秘"));
 
ArrayList list2 = clearRepeat(list);
System.out.println("新集合的元素是:"+ list2);
}
 
public static ArrayList clearRepeat(ArrayList list){
//创建一个新的集合
ArrayList newList = new ArrayList();
//获取迭代器
Iterator it = list.iterator();
while(it.hasNext()){
Book book = (Book) it.next(); //从旧集合中获取的元素
if(!newList.contains(book)){
//如果新集合没有包含该书籍,那么就存储到新集合中
newList.add(book);
}
}
return newList;
}
}

实现类LinkedList使用

LinkedList实现类内部实现主要是以指针方式连接的,相邻的两个元素地址不一样相邻。此实现不是同步的。如果多个线程同时访问一个链接列表,而其中至少一个线程从结构上修改了该列表,则它必须 保持外部同步。 
查看LinkedList函数定义实现:

public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{

LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。 
LinkedList 实现了: 
List 接口,能对它进行队列操作。 
Deque 接口,即能将LinkedList当作双端队列使用,支持在两端插入和移除元素。 
Cloneable接口,即覆盖了函数clone(),能克隆。 
java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。

实例

import java.util.LinkedList;
/*
使用LinkedList模拟堆栈的数据结构存储方式
1:栈 : 主要是用于实现堆栈数据结构的存储方式。
先进后出
push()
pop()
2:队列: 主要是为了让你们可以使用LinkedList模拟队列数据结构的存储方式。
先进先出
offer()
poll()
*/
class StackList{
LinkedList list;
 
public StackList(){
list = new LinkedList();
}
 
//进栈
public void add(Object o){
list.push(o);
}
 
//弹栈 : 把元素删除并返回。
public Object pop(){
return list.pop();
}
 
//获取元素个数
public int size(){
return list.size();
}
}
//使用LinkedList模拟队列的存储方式
class TeamList{
LinkedList list;
public TeamList(){
list = new LinkedList();
}
 
public void add(Object o){
list.offer(o);
}
 
public Object remove(){
return list.poll();
}
 
//获取元素个数
public int size(){
return list.size();
}
}
public class LinkedListTest {
public static void main(String[] args) {
TeamList list= new TeamList();
list.add("张三");
list.add("李四");
list.add("王五");
 
int size = list.size();
for(int i = 0 ; i<size ; i++){
System.out.println(list.remove());
}
}
}

发布了45 篇原创文章 · 获赞 17 · 访问量 7万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章