集合概述

Java中的集合,指一系列存储数据的接口和类,可以解决复杂的数据存储问题.

导包:import java.util.*;

简化的集合框架图如下:

List·列表

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也能用。

返回类型 方法名称 描述
boolean add(Object o) 添加元素
int size() 获取元素个数
boolean contains(Object o) 判断是否存在指定元素
boolean remove(Object o) 删除元素
void clear() 清空
boolean isEmpty() 判空
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不可用。

都是和索引相关的方法:

返回类型 方法名称 描述
void add(int index, E element) 指定位置添加元素
int indexOf(Object o) 获取指定元素的索引
E set(int index, E element) 替换指定位置的元素,返回更新前的元素
E get(int index) 获取指定索引的元素
E remove(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]

Java基础教程——List(列表)的更多相关文章

  1. Java基础教程(18)--继承

    一.继承的概念   继承是面向对象中一个非常重要的概念,使用继承可以从逻辑和层次上更好地组织代码,大大提高代码的复用性.在Java中,继承可以使得子类具有父类的属性和方法或者重新定义.追加属性和方法. ...

  2. Java基础教程:泛型基础

    Java基础教程:泛型基础 引入泛型 传统编写的限制: 在Java中一般的类和方法,只能使用具体的类型,要么是基本数据类型,要么是自定义类型.如果要编写可以应用于多种类型的代码,这种刻板的限制就会束缚 ...

  3. Java基础教程:HashTable与HashMap比较

    Java基础教程:HashTable与HashMap比较 1.  关于HashMap的一些说法: a)  HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体.HashMap的底层结 ...

  4. Java基础教程:对象比较排序

    Java基础教程:对象比较排序 转载请标明出处:http://blog.csdn.net/wangtaocsdn/article/details/71500500 有时候需要对对象列表或数组进行排序, ...

  5. Java基础教程:面向对象编程[3]

    Java基础教程:面向对象编程[3] 内容大纲 基础编程 获取用户输入 java.util.Scanner 是 Java5 的新特征,我们可以通过 Scanner 类来获取用户的输入.我们可以查看Ja ...

  6. Java基础教程(12)--深入理解类

    一.方法的返回值   当我们在程序中调用方法时,虚拟机将会跳转到对应的方法中去执行.当以下几种情况发生时,虚拟机将会回到调用方法的语句并继续向下执行: 执行完方法中所有的语句: 遇到return语句: ...

  7. Java基础教程:注解

    Java基础教程:注解 本篇文章参考的相关资料链接: 维基百科:https://zh.wikipedia.org/wiki/Java%E6%B3%A8%E8%A7%A3 注解基础与高级应用:http: ...

  8. Java基础教程:网络编程

    Java基础教程:网络编程 基础 Socket与ServerSocket Socket又称"套接字",网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个s ...

  9. Java基础教程(5)--变量

    一.变量 1.变量的定义   正如上一篇教程<Java基础教程(4)--面向对象概念>中介绍的那样,对象将它的状态存在域中.但是你可能仍然有一些疑问,例如:命名一个域的规则和惯例是什么?除 ...

  10. Java基础教程:Lambda表达式

    Java基础教程:Lambda表达式 本文部分内容引用自OneAPM:http://blog.oneapm.com/apm-tech/226.html 引入Lambda Java 是一流的面向对象语言 ...

随机推荐

  1. java关键字之super

    1.在子类的构造方法的第一条语句处调用其父类的构造方法: 如果父类提供了构造方法,并且父类不拥有无参构造方法,则要求子类拥有相同结构的构造方法.即,子类构造方法的参数个数和类型必须和父类的构造方法一致 ...

  2. [游记] 2020ZJOI 爆零记

    DAY 0 凌晨一点打完CF,身心俱疲,由于头痛和困意原本可做的E没做出来,懊悔地睡下,竟然又过了一个多小时才睡着? 早上醒来,感觉身体轻飘飘的,("我真的睡过觉了吗")--听说打 ...

  3. CF957E Contact ATC

    二维偏序(逆序对) 因为风速vf,-w<=vf<=w,因此我们可以算出每一艘船到达原点的时间的取值范围 即取vf=w和vf=-w时,记ai为当vf=w时的用时,记bi为当vf=-w时的用时 ...

  4. 面试重灾区——JVM内存结构和GC

    JVM介绍 1. JVM的体系架构(内存模型) 绿色的为线程私有,橘色的为线程共有 2. 类加载器 负责将.class文件加载到内存中,并且将该文件中的数据结构转换为方法区中的数据结构,生成一个Cla ...

  5. thinkPHPbiji

    ThinkPHP3.2验证码操作 在当前的控制器内 我这里是登录后台控制器 class LoginController extends Controller { public function ind ...

  6. Skip Lists: A Probabilistic Alternative to Balanced Trees 阅读笔记

    论文地址:https://15721.courses.cs.cmu.edu/spring2018/papers/08-oltpindexes1/pugh-skiplists-cacm1990.pdf ...

  7. Spider--补充--Requests--session&cookie

    # session 与 cookie # 可能大家对session已经比较熟悉了,也大概了解了session的机制和原理,但是我们在做爬虫时如何会运用到session呢,就是接下来要讲到的会话保持. ...

  8. CORS跨域请求:前后端分离

    1. 请求过滤器: /** * OncePerRequestFilter保证在任何Servlet容器中都是一个请求只执行一次的过滤器. */ public class CorsFilter exten ...

  9. fork系统调用关于如何让子进程先运行{wait(),waitpid(),sleep()}

    在父进程里面调用wait()和waitpid()可以确保子进程先运行,因为当子进程运行完后会变成僵尸进程,此时会发送一个信号给父进程,父进程接受到信号才会运行. 有人或许会问如果在父进程调用wait之 ...

  10. mysql中key和index的关系

    原文链接:https://blog.csdn.net/top_code/article/details/50599840