集合
为什么要学习集合,因为集合是Java中成熟的数据结构的实现,为什么要用这些数据结构,因为我们想要更合理的存储数据,数组有缺陷。集合关注的是怎么操作一个集合,把数据存进去取出来,删除,判断有与否,对数据的操作。
文章目录
类集概述
集合是常用类库里面很重要的一部分,与数组的概念相似,是数据的容器。普通对象数组最大的问题在于数组中的元素的个数是固定的,我们使用的动态扩容数组也是使用创建新数组来实现的。通过我们的学习,我们可以通过二叉树、链表等等的方法来完成可以无限制存储数据还不用扩容的这种机制。
在 Java 中为了方便用户操作各个数据结构,所以引入了类集的概念,有时候就可以把类集称为 java 对数据结构的实现。类集包含了很多的常见的数据结构,每种数据结构都有它擅长的点。
在整个类集中的,这个概念是从 JDK 1.2(Java 2)之后才正式引入的,最早也提供了很多的操作类,但是并没有完整的提出类集的完整概念。
类集中最大的几个操作接口:Collection、Map、Iterator(迭代器),这三个接口为以后要使用的最重点的接口。所有的类集操作的接口或类都在 java.util 包中。
Collection接口
Collection接口是整个Java类集结构中保存单值的最大操作接口,里面每次存储只能存一个对象的数据,此接口定义在java.util包中。此接口定义如下:
public interface Collection<E> extends Iterable<E>
它提供的方法有很多,一共有15个方法:
No. | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | public boolean add(E e) | 普通 | 向集合中插入一个元素 |
2 | public boolean addAll(Collection<? extends E> c) | 普通 | 向集合中插入一组元素 |
3 | public void clear() | 普通 | 清空集合中的元素 |
4 | public boolean contains(Object o) | 普通 | 查找一个元素是否存在 |
5 | public boolean containsAll(Collection<?> c) | 普通 | 查找一组元素是存在 |
6 | public boolean isEmpty() | 普通 | 判断集合是否为空 |
7 | public Iterator iterator() | 普通 | 为Iterator接口实例化 |
8 | public boolean remove(Object o) | 普通 | 从集合中删除一个对象 |
9 | boolean removeAll(Collction<?> c) | 普通 | 从集合中删除一组对象 |
10 | boolean retainAll(Collection<?> c) | 普通 | 判断是否没有指定的集合 |
11 | public int size() | 普通 | 求出集合中元素的个数 |
12 | public Object[] toArray() | 普通 | 以对象数组形式返回集合中的全部内容 |
13 | T[] toArray(T[] a) | 普通 | 指定操作的泛型类型,并把内容返回 |
14 | public boolean equals(Object o) | 普通 | 从Object类中覆写而来 |
15 | public int hashCode() | 普通 | 从Object类中覆写而来 |
因为Collection都是是接口,这些方法都是抽象的方法,此接口的全部子类或子接口就将全部继承以上接口中的方法。在开发中不会直接使用 Collection 接口。而使用其操作的子接口:List、Set。其中List里面存储的数据是允许重复的,Set里面存储的数据是不允许重复的。
List接口
在整个集合中 List 是 Collection 的子接口,里面的所有内容都是允许重复的。
List 子接口的定义:
public interface List<E> extends Collection<E>
此接口上任然使用了使用了泛型技术。此接口对于Collection接口来讲有如下的扩充方法:
No. | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | public void add(int index,E element) | 普通 | 在指定位置添加元素 |
2 | boolean addAll(int index,Collection<? extends E> c) | 普通 | 在指定位置处增加一组元素 |
3 | public E get(int index) | 普通 | 根据索引位置取出每一个元素 |
4 | public int indexOf(Object o) | 普通 | 据对象查找指定位置,找不到返回-1 |
5 | public int lastIndexOf(Object o) | 普通 | 从后面向前查找位置,找不到返回-1 |
6 | public ListIterator listIerator() | 普通 | 返回ListIterator接口的实例 |
7 | public ListiTerator listIterator(int index) | 普通 | 返回指定位置ListIterator接口实例 |
8 | public E set(int index,E element) | 普通 | 修改指定位置的内容 |
9 | public E set(int index,E element) | 普通 | 修改指定位置的内容 |
10 | List subList(int fromIndex,int toIndex) | 普通 | 返回自集合 |
在 List 接口中有以上 10 个方法是对已有的 Collection 接口进行的扩充。所以,证明List 接口拥有比 Collection 接口更多的操作方法。
了解了 List 接口之后,那么该如何使用该接口呢?需要找到此接口的实现类,常用的实现类有如下几个:
· ArrayList(95%)、Vector(4%)、LinkedList(1%)。
其中Vector是ArrayList的早期实现,它们的区别是一个线程安全一个线程不安全;而LinkdedList是通过链表结构进行存储。它们都支持List的方法。
ArrayList
ArrayList 是 List 接口的子类,此类的定义如下:
public class ArrayList<E> extends AbstractList<E>
implements List<E>,RandomAccess,Cloneable,Serializable
此类继承了AbstractList 类。AbstractList 是 List 接口的子类。AbstractList 是个抽象类,适配器设计模式。
示例:
package com.test.fourThree;
import java.util.ArrayList;
import java.util.Arrays;
/**
* 1. Arraylist采用无参构造器构造的集合在开始时长度默认10
*/
public class Demo1 {
public static void main(String[] args) {
//ArrayList: list集合下的一个实现类,使用的是数组结构,对于增删操作慢,查找快.
//必须传的是包装类,int不是具体的引用数据类型,Integer可以.单值存储
ArrayList<Integer> date = new ArrayList<>();//0
// 增加内容,此方法从Collection接口继承而来
date.add(100);
date.add(233);
// 增加内容,此方法是List接口单独定义的
date.add(1, Integer.valueOf("2"));
// 打印data对象调用toString()方法
System.out.println(date.get(2));
// 删除指定位置的元素
data.remove(1);
for(int x=0;x<data.size();x++){
//size()方法从Collection接口继承而来
System.out.print(data.get(x)+",")
}
}
}
Java中的包装类
基本类型 | 对应安装包 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
其中的ArrayList构造方法通过API进行查看:
构造器 | 描述 |
---|---|
ArrayList() | 构造一个初始容量为10的空列表 |
ArrayList(int initialCapacity) | 构造具有指定初始容量的空列表 |
ArrayList(Collection<? extends E> c) | 按照集合的迭代器返回的顺序构造一个包含指定集合元素的列表 |
当不传参数时它会自动构造一个初始容量为10的空列表,在我们存储一个数据较多的内容的时候,建议使用一参构造方法,因为使用无参构造方法的时候它会一种在进行扩容影响了程序的效率。
其中add方法当中增加一个数据,无论存储成功与否放回的布尔类型数据都是true,点开看一下源码
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
Vector
与 ArrayList 一样,Vector 本身也属于 List 接口的子类,此类的定义如下:
public class Vector<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable
此类与 ArrayList 类一样,都是 AbstractList 的子类。所以,此时的操作只要是 List 接口的子类就都按照 List 进行操作。与新的集合实现不同,Vector是同步的(排着队走),如果不需要线程安全实现,建议使用ArrayList代替Vector。
因为Vector与ArrayList使用方法基本一致,就不在进行代码演示,我们看一看它的构造方法:
构造器 | 描述 |
---|---|
Vector() | 构造一个空向量,使其内部数据数组的大小为10,其标准容量增量为零 |
Vector(int initialCapacity) | 构造一个具有指定初始容量且容量增量等于零的空向量 |
Vector(int initialCapacity,int capacityIncrement) | 构造具有指定初始容量和容量增量的空向量 |
Vector(Collection<? extends E> c) | 按照集合的迭代器返回的顺序构造一个包含指定集合元素的向量 |
Vector提供了四个构造方法,其中无参构造方法与ArrayList有一些出入,Vecrot每次扩容可以指定增加的量,而ArrayList是每次扩容1.5倍。再看一看第三个Vector(a, b),其中a表示初始容量,b表示每次扩容增加的量,当b=0的时候,扩容的是长度就为a。
ArrayList类与Vector类的区别:
LinkedList
此类的使用几率是非常低的,但是此类的定义如下:
public class LinkedList<E> extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, Serializable
此类继承了 AbstractList,所以是 List 的子类。但是此类也是 Queue 接口的子类,Queue 接口定义了如下的方法:
方法名称 | 类型 | 描述 | |
---|---|---|---|
1 | public boolean addd(E e) | 普通 | 增加元素,如果容量限制,并且以满,则抛出异常 |
2 | public E element() | 普通 | 获取元素,取出后不删除元素,如果队列为空则抛出异常 |
3 | boolean offer(E e) | 普通 | 添加元素,若有容量限制且以存满,就无法添加但不抛出异常,返回false |
4 | E peek() | 普通 | 取得头元素,取出后不删除,如果队列为空,则返回null |
5 | E poll() | 普通 | 取得头元素,取出后删除,如果队列为空,则返回null |
6 | E remove() | 普通 | 删除当前元素,如果队列为空则抛出异常 |
示例:
package com.test.fourThree;
import java.util.LinkedList;
public class Demo2 {
public static void main(String[] args) {
//LinkedList : 使用的是双向链表结构,对于增加删除快,查找慢.
//add,remove,get()
LinkedList<Integer> date = new LinkedList<>();
//首部添加
data.addFrinst(88);
data.addFrinst(99);
//打印并删除99
System.out.println(data.removeFrinst());
//模拟栈结构
//压栈,先进后出,后进先出
date.push(100);
date.push(300);
//弹栈
Integer i = date.pop();
System.out.println(i);
}
}
LinkedList跟ArrayList是互补的状态,ArrayList它增删操作慢,查找快,而LinkedList它增加删除快,查找慢。我们就可以根据自己的业务需求选择不同的类进行数据操作。
而因为LinkedList使用的是双向链表结构,就可以使用它模拟栈、队列来使用。
Iterator与ListIterator(迭代器)
迭代器用于遍历集合。
Iterator此接口定义如下:
public interface Iterator<E>
LisrIterator此接口定义如下:
public interface ListIterator<E>
extends Iterator<E>
之前我们遍历集合是这样的:
package com.test.fourThree;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
public class Demo3 {
public static void main(String[] args) {
//创建集合对象
ArrayList<Integer> date = new ArrayList<>();
date.add(100);
date.addFirst(200);
date.addLast(304);
date.add(2