Java基础教程——List(列表)

集合概述

Java中的集合,指一系列存储数据的接口和类,可以解决复杂的数据存储问题.
导包:import java.util.*;

简化的集合框架图如下:
1648799-20190713015737098-561029802.png

List·列表

1648799-20190713015756602-206352143.png

ArrayList

List是一个接口:

public interface List<E> extends Collection<E>{...}

ArrayList是最常用的一种List的子类(当然也实现了其他接口,也继承了父类)。

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable{...}

ArrayList用法类似于数组,且其容量可按需要动态调整,亦被称为动态数组。

数组最大的痛点是大小固定(可以改变,但是很麻烦)
ArrayList底层是用数组实现的,所以名字里带了个数组(Array)。

示例:泰国旅行团
本示例展示了在List中使用泛型的必要性。
设定:泰国旅行团,约定只收Girl,有一个Boy混入,编译没问题,接机(输出)时按Girl接收,会出错。

import java.util.ArrayList;
import java.util.List;
public class TestArrayList {
    public static void main(String[] args) {
        // 开团
        List _泰国五日游 = new ArrayList();
        Girl _g1 = new Girl();
        Girl _g2 = new Girl();
        Girl _g3 = new Girl();
        _泰国五日游.add(_g1);
        _泰国五日游.add(_g2);
        _泰国五日游.add(_g3);
        // 混入
        Boy _b = new Boy();
        _泰国五日游.add(_b);
        System.out.println("...");
        // 接机
        for (int i = 0; i < _泰国五日游.size(); i++) {
            Girl g = (Girl) _泰国五日游.get(i);
        }
    }
}
class Boy {
}
class Girl {
}

代码没错,运行出错(对象本是Boy类型,偏要转成Girl类型---类型转换异常)

Exception in thread "main"

java.lang.ClassCastException

ArrayList<E>使用泛型

JDK 1.5之后,引入了泛型,可指定列表内元素的类型。类型不符合的元素不允许加入数组,这样就能再编译阶段发现错误,避免运行时出错的尴尬。

        // 开团
        List<Girl> _泰国五日游 = new ArrayList<Girl>();
        ……
        // 混入
        Boy _b = new Boy();
        //提示代码有错误:     _泰国五日游.add(_b);

遍历

import java.util.*;
public class ListTraversal {
    public static void main(String[] args) {
        m010Traversal();
        m020线程安全版();
    }
    private static void m010Traversal() {
        System.out.println("=====遍历");
        List<String> lst = new ArrayList<String>();
        lst.add("孙行者");
        lst.add("猪八戒");
        lst.add("沙悟净");
        // (1)
        for (int i = 0; i < lst.size(); i++) {
            System.out.println("for遍历集合:" + lst.get(i));
        }
        // (2)
        for (String s : lst) {
            System.out.println("foreach遍历集合:" + s);
        }
        // (3)Iterator,迭代器。用于遍历(迭代访问)集合中的元素
        Iterator<String> it = lst.iterator();
        while (it.hasNext()) {
            System.out.println("Iterator遍历:" + it.next());
        }
        // (4)Java 8:调用forEach()方法遍历集合
        lst.forEach(s -> System.out.println("Lambda表达式遍历集合:" + s));
    }
    // API文档上说ArrayList不是同步的,即多线程环境下不安全
    // Collections.synchronizedList(...)将其转为线程安全的列表
    private static void m020线程安全版() {
        System.out.println("=====线程安全版");
        List<String> lst = new ArrayList<String>();
        lst.add("孙行者");
        lst.add("猪八戒");
        lst.add("沙悟净");
        // 解决线程安全问题
        List<String> synList = Collections.synchronizedList(lst);
        for (String s : synList) {
            System.out.println("foreach遍历集合:" + s);
        }
    }
}

迭代器原理gif:https://www.cnblogs.com/tigerlion/p/10706386.html

更多方法

Collection相关方法

这些方法属于Collection类,可以被子类继承,因此通用性较强,不仅List能用,Set也能用。

返回类型方法名称描述
booleanadd(Object o)添加元素
intsize()获取元素个数
booleancontains(Object o)判断是否存在指定元素
booleanremove(Object o)删除元素
voidclear()清空
booleanisEmpty()判空
Object[]toArray()集合转数组
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class TestCollection {
    public static void main(String[] args) {
        Collection<String> list = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            list.add("s" + i);
        }
        System.out.println("size():" + list.size());
        // 查找
        boolean contains = list.contains("s1");
        System.out.println("contains(Object o):" + contains);
        boolean empty = list.isEmpty();
        System.out.println("isEmpty():" + empty);
        // 集合转数组
        Object[] array = list.toArray();
        System.out.println("toArray():" + Arrays.toString(array));
        // 删除
        list.remove("s1");
        System.out.println("remove(Object o):" + list);
        list.clear();
        System.out.println("clear():" + list);
    }
}
List相关方法

List的派生类对象可以使用,Set不可用。
都是和索引相关的方法:

返回类型方法名称描述
voidadd(int index, E element)指定位置添加元素
intindexOf(Object o)获取指定元素的索引
Eset(int index, E element)替换指定位置的元素,返回更新前的元素
Eget(int index)获取指定索引的元素
Eremove(int index)删除指定索引的元素
import java.util.ArrayList;
import java.util.List;
public class TestList {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            list.add("s" + i);
        }
        list.add(3, "舍卫国");
        int indexOf = list.indexOf("舍卫国");
        System.out.println("List.indexOf(Object o):" + indexOf);
        String set = list.set(0, "舍卫国赵长者");// 返回更新前的元素
        System.out.println("List.set(int index, E element):" + set);
        String get = list.get(0);
        System.out.println("List.get(int index):" + get);
        String remove = list.remove(3);// 返回被删除的元素
        System.out.println("List.remove(int index):" + remove + list);
    }
}

源码浅析:

ArrayList底层是通过数组实现,查询快、增删慢。API文档上说ArrayList不是同步的,即多线程环境下不安全,但是效率高。

ArrayList每次扩容至1.5倍。

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        // >>1:右移动1位=除以2
        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);
    }

Vector

和ArrayList用法一致。

元素超过它的初始大小线程安全效率
ArrayList*150%×
Vector*200%

Vector是一个比较老的类,在JDK 1.0即已出现,不推荐使用(蓝桥杯的练习题中出现过Vector,在那道题中只要知道它的用法和ArrayList一样就行)。

虽然Vector是线程安全的,但是在线程安全方面也不推荐使用。推荐方案如下:

List<String> synList = Collections.synchronizedList(lst);

LinkedList

ArrayList使用数组实现,查询快,增删慢;
LinkedList使用链表实现,查询慢,增删快,适用于经常插入、删除大量数据的场合,适合采用迭代器Iterator遍历。
如果仅仅是在列表末尾插入数据,LinkedList的效率低于ArrayList,因为LinkedList调用add时需要创建对象,而ArrayList只是在容量不够时才扩容。

LinkedList实现了List和Deque(双端队列)接口。

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

特色方法(此时不能使用多态):

特色方法解释
addFirst()头部添加
addLast()尾部添加
removeFirst()头部删除
removeLast()尾部删除
push()入栈,等效于addFirst()
pop()出栈,等效于removeFirst()
offer()入队列,等效于addLast()
poll()出队列,等效于removeFirst()
import java.util.LinkedList;
public class TestLinkedList {
    public static void main(String[] args) {
        LinkedList<String> link = new LinkedList<String>();
        // addFirst:头部添加数据
        link.addFirst("A");
        link.addFirst("B");
        link.addFirst("C");
        link.removeFirst();
        System.out.println(link);
        // addLast:尾部添加数据
        link.addLast("A");
        link.addLast("B");
        link.addLast("C");
        link.removeLast();
        System.out.println(link);
        link.clear();// 清空
        // push:将元素推入栈,等效于addFirst()
        link.push("A");
        link.push("B");
        link.push("C");
        // pop:出栈,调用的是removeFirst()
        link.pop();
        System.out.println("栈" + link);
        link.clear();// 清空
        // 将指定元素添加到此列表的末尾(最后一个元素)。
        // offer:入队列:调用的是add方法,add又调用linkLast,和addLast一样
        link.offer("A");
        link.offer("B");
        link.offer("C");
        // poll:出队列:调用的是removeFirst()
        link.poll();
        System.out.println("队列" + link);
    }
}

[B, A]
[B, A, A, B]
栈[B, A]
队列[B, C]


*ArrayDeque·栈和队列

  • 栈:先进后出
  • 队列:先进先出

Deque(双端队列),是Queue的子接口,其实现类ArrayDeque和ArrayList的实现机制相似,使用Object[]数组存储集合元素,当容量不足时,可以重新分配数组。

ArrayDeque可以当做栈和队列使用。

import java.util.*;
public class TestArrayDeque {
    public static void main(String[] args) {
        m030栈();
        m040队列();
    }
    static void m030栈() {
        System.out.println("=====栈");
        // push,pop(poll也可以)
        Deque<String> stack = new ArrayDeque<String>();
        stack.push("A");
        System.out.println(stack);// [A]
        stack.push("B");
        System.out.println(stack);// [B, A]
        stack.push("C");
        System.out.println(stack);// [C, B, A]
        System.out.println("peek()访问第一个元素:" + stack.peek());// C
        System.out.println("pop()弹出:" + stack.pop());// C
        System.out.println(stack);// [B, A]
    }
    static void m040队列() {
        System.out.println("=====队列");
        // offrt,poll(pop也可以)
        Deque<String> queue = new ArrayDeque<String>();
        queue.offer("A");// [A]
        System.out.println(queue);
        queue.offer("B");// [A, B]
        System.out.println(queue);
        queue.offer("C");// [A, B, C]
        System.out.println(queue);
        System.out.println("peek()访问第一个元素:" + queue.peek());// A
        System.out.println("poll()弹出:" + queue.poll());// A
        System.out.println(queue);// [B, C]
    }
}

运行结果:

=====栈
[A]
[B, A]
[C, B, A]
peek()访问第一个元素:C
pop()弹出:C
[B, A]
=====队列
[A]
[A, B]
[A, B, C]
peek()访问第一个元素:A
poll()弹出:A
[B, C]

转载于:https://www.cnblogs.com/tigerlion/p/11179202.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值