集合概述

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. 【总结】IP

    一. IP基本认识 1.IP 在 TCP/IP 参考模型中处于第三层,也就是网络层. 网络层的主要作用是:实现主机与主机之间的通信,也叫点对点(end to end)通信 2.网络层与数据链路层有什么 ...

  2. Verification of WISHBONE I2C Master Core(IRUN+Simvision)

    一.前言 很久没写技术博客了,有些懈怠,生活还得继续折腾.转眼工作一年多,时间越长越发觉得自己知之甚少,当然这跟IC行业技术密集有关.用空余时间在opencores网站上下载些小的IP看看 验证下,让 ...

  3. 【译】Rust中的array、vector和slice

    原文链接:https://hashrust.com/blog/arrays-vectors-and-slices-in-rust/ 原文标题:Arrays, vectors and slices in ...

  4. Ubuntu Kylin 部署 .Net Core 应用程序

    前几日在头条上看到了 优麒麟(https://www.ubuntukylin.com/) ,出于好奇,就下载安装玩玩,整体感觉不错.当然这不是重点,重点是要在它上面部署的.Net Core 应用程序. ...

  5. pandas模块常用函数解析之Series(详解)

    pandas模块常用函数解析之Series 关注公众号"轻松学编程"了解更多. 以下命令都是在浏览器中输入. cmd命令窗口输入:jupyter notebook 打开浏览器输入网 ...

  6. 简单入门Rabbitmq

    什么是RabbitMQ RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写.支持多种客户端,如:Python.Ruby..NET.Java.JMS.C.PHP.ActionScr ...

  7. 聊聊Go代码覆盖率技术与最佳实践

    "聊点干货" 覆盖率技术基础 截止到Go1.15.2以前,关于覆盖率技术底层实现,以下知识点您应该知道: go语言采用的是插桩源码的形式,而不是待二进制执行时再去设置breakpo ...

  8. 知识补充之Django缓存

    缓存 简单概括就是将对数据库操作查询所得到的数据放入另外一台机器上(缓存)中,当用户再次请求时,直接去缓存中拿,避免对数据库的频繁操作,加快数据的显示时间,需要知道的是,缓存里面的数据一般都设置有超时 ...

  9. unix进程间通信方式(IPC)

    unix进程间通信方式(IPC) 管道(Pipe):管道可用于具有亲缘关系进程间的通信,允许一个进程和另一个与它有共同祖先的进程之间进行通信. 命名管道(named pipe):命名管道克服了管道没有 ...

  10. Docker 实战(2)- 配置 Jenkins 容器上的持续集成环境

    如果你还想从头学起 Docker,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1870863.html 搭建 Jenkins 容器 就是 ...