文章目录
集合
集合的概念
首先, 我们来聊一聊数组, 我们知道, 数组是同一类元素的有序集合, 但是数组却又一个致命的缺点, 那就是数组一旦被定义, 那就无法再对其容量进行改变了, 但是我们的开发或者日常生活中, 经常要存储一些可变的数据集合, 这时数组便不能满足我们的需要, 我们就需要一些能够
动态增长长度的容器
来保存我们的数据。而我们需要对数据的保存的各种逻辑可能可能是多种多样的,于是就有了各种各样的数据结构。
Java中对于各种数据结构的实现,就是我们用到的集合
。
集合API
Java的集合类(集合API,集合框架)是Java数据结构的实现,是由很多的接口、抽象类、具体类组成的,都位于java.util包中。
集合的体系图如下:
Collection接口
Collection接口–定义了存取一组对象的方法,其子接口Set和List分别定义了存储方式。
Set中的数据对象没有顺序且不可以重复(无序,不重复)。
List中的数据对象有顺序且可以重复(有序且重复)。
Collection中定义的集合共有方法:
返回值类型 | 方法名 | 功能 |
---|---|---|
boolean | add(Object element) | 添加元素 |
boolean | addAll(Collection c) | 将制定集合的元素添加到此集合中 |
boolean | remove(Object element) | 删除指定元素 |
boolean | removeAll(Collection c) | 删除指定集合 不包含时,删除相交的元素 |
void | clear() | 清空集合 |
int | size() | 集合内的元素个数 |
boolean | isEmpty() | 判断集合是否为空 |
boolean | contains(Object element) | 判断集合中是否包含指定元素 |
boolean | containsAll(Collection c) | 判断是否包含某个集合 |
boolean | retainAll(Collection c) | 求交集,集合数据发生变化返回true,不变返回false |
default boolean | removeIf() | 条件删除 |
注意
:这里有一个需要注意的地方,使用其添加方法添加基本数据类型时会默认调用valueof()方法装箱,因为**集合只能存储引用数据类型。**例如:
import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo {
public static void main(String[] args) {
Collection data = new ArrayList();
//集合只能存储引用类型
data.add("hello!");
//添加基本类型都会将基本类型装箱为引用类型
data.add(1);//这里添加1会,将1转换为Integer类型
data.add("World");
data.remove(1);
System.out.println(data);
}
}
代码示例
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
//Collection中的共有的方法
public class Preview1 {
public static void main(String[] args) {
Integer [] arr1 = {1,2,3};
Collection<Integer> arr = new ArrayList<>(20);
for (int i = 0; i<15;i++){
arr.add(i);
}
/*
boolean add(Object element);
boolean addAll(Collection c);
boolean remove(Object element);
boolean removeAll(Collection c);删除指定集合 不包含时,删除相交的元素
void clear();
int size();
boolean isEmpty();
boolean contains(Object element);
boolean containsAll(Collection c);
boolean retainAll(Collection c); 求交集,集合数据发生变化返回true,不变返回false
*/
System.out.println(arr.add(100));//true
System.out.println(arr);//[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 100]
System.out.println(arr.addAll(Arrays.asList(arr1)));
System.out.println(arr);//[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 100, 1, 2, 3]
System.out.println(arr.remove(1));//[0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 100, 1, 2, 3]
System.out.println(arr);
System.out.println(arr.removeAll(Arrays.asList(arr1)));
System.out.println(arr);//[0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 100]
System.out.println(Arrays.toString(arr1));//[1, 2, 3]
// arr.clear();
// System.out.println(arr);//[]
System.out.println(arr.size());//13
System.out.println(arr.isEmpty());//false
System.out.println(arr.contains(10));//true
System.out.println(arr.containsAll(Arrays.asList(arr1)));//true
System.out.println(arr.retainAll(Arrays.asList(arr1)));//true
//removeIf() 条件删除
System.out.println(arr.removeIf(new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
return integer.equals(0);
}
}));
System.out.println(arr);
}
}
List接口
有序:按照添加顺序排列。
可以有重复元素。
List继承了Collection接口, 有三个实现的类:
ArrayList: 数组列表, 数据采用数组方式存储
LinkedList: 链表
Vector: 数组列表, 添加了同步锁, 线程安全
List接口的常用方法
List接口的方法在它的实现类中都可以使用。(Collection中定义的方法这里都可以使用)
返回值 | 方法名 | 功能 |
---|---|---|
void | add(Object obj) | 将Object类型的元素添加到集合末尾 |
void | add(int index, Object obj) | 将Object类型的元素添加到指定位置 |
void | addAll(Collection c) | 给集合添加一个新集合,也可以加上位置 |
void | remove(int index) | 删除指定位置的元素 |
void | remove(Object obj) | 删除指定元素(集合中第一次出现) |
void | removeAll(Collection c ) | 删除指定集合,不包含时删除相交得的元素 |
set(int index,Object o) | 将指定索引的元素替换为指定的元素 | |
get(int index) | 返回指定索引位置的元素 | |
boolean | contains(Object o) | 判断集合中是否包含指定元素 |
boolean | containsAll(Collection c) | 判断集合中是否包含指定集合 |
int | indexOf(Object o) | 返回指定元素第一次出现的索引值,没有就返回-1 |
boolean | isEmpty() | 判断集合是否为空 |
int | lastIndexOf(Object) | 返回元素最后一次出现的索引值 |
int | size() | 返回此集合的元素数量 |
List | subList(int formIndex,int toIndex) | 截取指定区间返回一个集合 |
void | clear( ) | 清空集合 |
asList, toArray(), toArray(T[] a) 的用法
import java.lang.String;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class Preview1 {
private static Object String;
public static void main(String[] args) {
String [] arr = {"1","2","3","4"};
//asList--->Arrays中的方法,可以将一个数组转化为集合
Collection<String> list = new ArrayList();
System.out.println(list.addAll(Arrays.asList(arr)));
System.out.println(list);
//toArray()--->返回一个类型为Object[]的包含集合中的所有元素的数组
Object [] arr1 = list.toArray();
System.out.println(Arrays.toString(arr1));
//返回包含此集合中所有元素的数组; 返回的数组的运行时类型是指定数组的运行时类型
String[] arr2 = list.toArray(new String[list.size()]);
System.out.println(Arrays.toString(arr2));
}
}
代码示例
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
//List接口的常用方法
public class ListDemo {
public static void main(String[] args) {
List list = new LinkedList();
//添加元素---末尾
list.add("中");
list.add(1);
list.add(true);
System.out.println(list);
//添加元素到指定位置
list.add(1,"风");
//添加一个新集合
Collection c = new LinkedList();
c.add(1);
c.add(2);
c.add(3);
list.addAll(c);
System.out.println(list);
//添加一个新集合到指定位置
list.addAll(2,c);
System.out.println(list);
//删除指定位置元素
list.remove(1);
System.out.println(list);
//删除指定元素
list.remove(1);
System.out.println(list);
//修改指定位置元素---返回这个位置之前的元素
System.out.println(list.set(3,"天"));
//查询指定位置元素
System.out.println(list.get(3));
//判断集合送是否包含指定元素
System.out.println(list.contains("天"));
//判断是否包含指定集合
System.out.println(list.containsAll(c));
//返回元素第一次出现的索引值,没有就返回-1
System.out.println(list.indexOf("风"));
//判断集合是否为空
System.out.println(list.isEmpty());
//返回元素最后出现一次的索引值
System.out.println(list.lastIndexOf(3));
//返回集合中的元素数量
System.out.println(list.size());
//截取集合中的指定区间
System.out.println(list.subList(2,5));
//清空集合
list.clear();
}
}
实现类:ArrayList
ArrayList是实现了长度可变的数组, 在内存中分配连续的空间。
**优点:**底层数据结构是数组,查询快,增删慢,遍历元素和随机访问元素的效率高。
**缺点:**线程不安全。
ArrayList的常用方法(list接口中的方法在ArrayList中都可用):
返回值 | 方法名 | 功能 |
---|---|---|
void | ensureCapacity(int minCapacity) | 自行增加容量,以保证它最少有指定数量的元素 |
protected void | removeRange(int f,int e) | 删除指定区间的元素,需要继承ArrayList才能使用 |
boolean | retainAll(Collection c) | 仅保留此集合中在包含指定集合的元素 |
void | trimToSize() | 修改当前集合的容量大小为元素个数数量 |
void | sort(比较器) | 需要传入一个比较器进行排序 |
代码示例
import java.util.ArrayList;
import java.util.Comparator;
public class ArrayListDemo extends ArrayList {
public static void main(String[] args) {
ArrayList list = new ArrayList();
//添加元素---末尾
list.add("中");
list.add(1);
list.add(true);
System.out.println(list);
//添加元素到指定位置
list.add(1, "风");
//添加一个新集合
ArrayList c = new ArrayList();
c.add(1);
c.add(2);
c.add(3);
list.addAll(c);
System.out.println(list);
//自行增加容量---让其有最少为指定的容量
list.ensureCapacity(20);
//删除指定区间,这是一个受保护权限,需要继承ArrayList才能在子类中调用
ArrayListDemo list1 = new ArrayListDemo();
list1.add(0);
list1.add(1);
list1.add(2);
list1.add(3);
list1.add(4);
list1.add(5);
list1.removeRange(1,4);
System.out.println(list1);
//仅保留此集合中包含在指定集合中的元素
list.retainAll(c);
System.out.println(list);
//sort 传入一个比较器进行排序
ArrayList<Integer> list2 = new ArrayList<>();
list2.add(3);
list2.add(7);
list2.add(5);
list2.add(0);
list2.add(1);
list2.sort(new pd());
System.out.println(list2);
}
}
class pd implements Comparator<Integer>{
@Override
public int compare(Integer o1, Integer o2) {
return o1-o2;
}
}
实现类:LinkedList
LinkedList采用链表存储的方式。插入、删除元素时效率较高。
优点:底层数据结构使用的是链表,查询快、增删慢。
缺点:线程不安全。
LinkedList的常用方法和ArrayList的差不多,也都实现了List接口和Collection接口,底层以链表的形式存储
代码示例
import java.util.*;
public class LinkedListDemo extends LinkedList{
public static void main(String[] args) {
LinkedList list = new LinkedList();
//添加元素---末尾
list.add("中");
list.add(1);
list.add(true);
System.out.println(list);
//添加元素到指定位置
list.add(1,"风");
//添加一个新集合
Collection c = new LinkedList();
c.add(1);
c.add(2);
c.add(3);
list.addAll(c);
System.out.println(list);
//添加一个新集合到指定位置
list.addAll(2,c);
System.out.println(list);
//删除指定位置元素
list.remove(1);
System.out.println(list);
//删除指定元素
list.remove(1);
System.out.println(list);
//修改指定位置元素---返回这个位置之前的元素
System.out.println(list.set(3,"天"));
//查询指定位置元素
System.out.println(list.get(3));
//判断集合送是否包含指定元素
System.out.println(list.contains("天"));
//判断是否包含指定集合
System.out.println(list.containsAll(c));
//返回元素第一次出现的索引值,没有就返回-1
System.out.println(list.indexOf("风"));
//判断集合是否为空
System.out.println(list.isEmpty());
//返回元素最后出现一次的索引值
System.out.println(list.lastIndexOf(3));
//返回集合中的元素数量
System.out.println(list.size());
//截取集合中的指定区间
System.out.println(list.subList(2,5));
//删除指定区间,这是一个受保护权限,需要继承ArrayList才能在子类中调用
LinkedListDemo list1 = new LinkedListDemo();
list1.add(0);
list1.add(1);
list1.add(2);
list1.add(3);
list1.add(4);
list1.add(5);
list1.removeRange(1,4);
System.out.println(list1);
//sort 传入一个比较器进行排序
ArrayList<Integer> list2 = new ArrayList<>();
list2.add(3);
list2.add(7);
list2.add(5);
list2.add(0);
list2.add(1);
list2.sort(new pd());
System.out.println(list2);
}
}
class pd implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
return o1-o2;
}
}
实现类:Vector
Vector底层实现就是数组,和ArrayList是一致的,但是Vector添加了同步锁synchronized,保证了线程安全。
效率测试
测试ArrayList和LinkedList的存入和查找效率
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
//测试ArrayList和LinkedList存,查效率
public class Test1 {
public static void main(String[] args) {
ArrayList list = new ArrayList();
Date date1 = new Date();
for (int i = 0; i < 10000; i++) {
list.add("a");
}
for (int i = 0; i < 90000; i++) {
list.add(2500,"a");
}
Date date2 = new Date();
System.out.println("ArrayList存10万次的时间:"+(date2.getTime()-date1.getTime()));
// ArrayList存10万次的时间:521ms
Date date3 = new Date();
for (int i = 0; i < 100000; i++) {
list.get(2500);
}
Date date4 = new Date();
System.out.println("ArrayList查10万次的时间:"+(date4.getTime()-date3.getTime()));
//ArrayList查10万次的时间:0ms
LinkedList list1 = new LinkedList();
Date date5 = new Date();
for (int i = 0; i < 10000; i++) {
list1.add("a");
}
for (int i = 0; i < 90000; i++) {
list1.add(2500,"a");
}
Date date6 = new Date();
System.out.println("LinkedList存10万次的时间:"+(date6.getTime()-date5.getTime()));
//LinkedList存10万次的时间:399ms
Date date7 = new Date();
for (int i = 0; i < 100000; i++) {
list1.get(2500);
}
Date date8 = new Date();
System.out.println("LinkedList查10万次的时间:"+(date8.getTime()-date7.getTime()));
//LinkedList查10万次的时间:401ms
}
}
List接口的迭代
for循环
语法格式:for(int i;i < list.size() ; i++){…}
注意:
for循环有一个缺陷,就是在删除元素的时候,集合的长度会变小,但是索引 i 的值却在不断变大,这就会出现删不尽的情况,因此我们总是需要做一些小小的处理,请看代码。
代码示例
import java.util.ArrayList;
//遍历数组--for循环
public class ForDemo {
public static void main(String[] args) {
ArrayList<String> arr = new ArrayList<>();
arr.add("a");
arr.add("s");
arr.add("d");
arr.add("e");
arr.add("s");
System.out.println(arr);
for (int i = 0; i < arr.size(); i++) {
System.out.println(arr.get(i));
}
//删除元素后,集合的长度也发生了变化,但是索引 i 的值一直在变大,会出现删不尽的情况
for (int i = 0; i < arr.size(); i++) {
arr.remove(i);
//使用 i-- 将i的值不断变小,等于说每一次都在删除敌意个数
i--;
}
System.out.println(arr);//[s, e]
}
增强for循环
语法格式:for(Object obj:list){System. out. println(obj);}
**注意:**增强for循环,不允许在遍历的时候对元素进行操作,否则会抛出异常,但是我们可以进行一次操作,比如删除一个元素后立刻break,趁着jvm还没反应过来抛出异常时,我们就跳出去。
代码示例
import java.util.ArrayList;
//迭代---增强for循环
public class ForeachDemo {
public static void main(String[] args) {
ArrayList<String> arr = new ArrayList<>();
arr.add("a");
arr.add("s");
arr.add("d");
arr.add("e");
arr.add("s");
System.out.println(arr);
for (String s: arr) {
System.out.println(s);
}
//增强for循环,不允许遍历时对元素进行操作,否则会报错:ConcurrentModificationException
//但是可以进行一次操作,比如删除已次元素后,趁着异常还没抛出时立刻跳出
for (String s: arr) {
arr.remove(s);
break;
}
System.out.println(arr);//[s, d, e, s]
}
}
迭代器–iterator
这是Collection接口中提供的操作,直接上代码:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Preview2 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
Iterator<String> iterator = arr.iterator();
//hasNext() 检测迭代器中是否还有元素
while(iterator.hasNext()){
//每次都从arr中拿出一个元素
String s = iterator.next();
if (s.equals("c")){
//这里不能使用原本的集合对象,因为迭代器中不能直接调用集合对象,需要使用iterator作为中间人
iterator.remove();
}
}
System.out.println(arr);
}
}