集合
- 什么是集合
对象的容器,实现了对象的常用操作。类似数组的功能
- 集合与数组的区别
- 数组的长度固定,集合的长度不固定
- 数组可以存储基本类型和引用类型,而集合只能存储引用类型
- 集合的存储位置
集合存放在 java.util.* 包下
Collection集合
- Collection体系集合
- 什么是Collection接口
Collection 层次结构 中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。JDK 不提供此接口的任何直接 实现:它提供更具体的子接口(如 Set 和 List)实现。此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection
- Collection接口的方法
用法 | 解释 |
---|---|
boolean add(E e) | 确保此 collection 包含指定的元素(可选操作)。 |
boolean addAll(Collection<? extends E> c) | 将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。 |
void clear() | 移除此 collection 中的所有元素(可选操作)。 |
boolean contains(Object o) | 如果此 collection 包含指定的元素,则返回 true。 |
boolean containsAll(Collection<?> c) | 如果此 collection 包含指定 collection 中的所有元素,则返回 true。 |
boolean equals(Object o) | 比较此 collection 与指定对象是否相等。 |
int hashCode() | 返回此 collection 的哈希码值。 |
boolean isEmpty() | 如果此 collection 不包含元素,则返回 true。 |
Iterator iterator() | 返回在此 collection 的元素上进行迭代的迭代器。 |
boolean remove(Object o) | 从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。 |
boolean removeAll(Collection<?> c) | 移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。 |
boolean retainAll(Collection<?> c) | 仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。 |
int size() | 返回此 collection 中的元素数。 |
Object[ ] toArray() | 返回包含此 collection 中所有元素的数组。 |
T[ ] toArray(T[ ] a) | 返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同。 |
- Collection实例
public class Demo1 {
public static void main(String[] args) {
Collection collection = new ArrayList();
//增加元素
collection.add("111");
collection.add("222");
collection.add("aaa");
System.out.println("元素个数"+collection.size());
System.out.println(collection);
System.out.println("=========================================");
//删除元素
collection.remove("111");
System.out.println("元素个数"+collection.size());
System.out.println(collection);
//collection.clear();//删除所有元素
System.out.println("=========================================");
//遍历元素
//1.使用foreaech 增强for循环
for (Object object:collection
) {
System.out.println(object);
}
//2.使用迭代器(迭代器是专门用来遍历集合的一种方式)
//迭代器具有的三个方法
//hasNext();有没有下一个元素
//next();获取下一个元素
//remove();删除当前元素
Iterator iterator=collection.iterator();
while (iterator.hasNext()) {
Object ob = iterator.next();
System.out.println(ob);
}
//我们知道集合中是Stirng类型就可以直接强制转换
Iterator iterator2=collection.iterator();
while (iterator2.hasNext()){
String s=(String) iterator2.next();
System.out.println(s);
//collection.remove(s);
System.out.println(collection);
iterator2.remove();//删除当前元素,指针是不动的
}
System.out.println("元素个数"+collection.size());
System.out.println(collection);
System.out.println("=========================================");
//判断
//判断是否有这个元素,有返回ture
System.out.println(collection.contains("222"));
//判断集合是否为空,为空返回ture
System.out.println(collection.isEmpty());
}
}
List子接口
- List接口特点
- 此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。
- 有序,有下标,元素可重复
- List接口的方法
用法 | 解释 |
---|---|
boolean add(E e) | 向列表的尾部添加指定的元素(可选操作)。 |
void add(int index, E element) | 在列表的指定位置插入指定元素(可选操作)。 |
boolean addAll(Collection<? extends E> c) | 添加指定 collection 中的所有元素到此列表的结尾,顺序是指定 collection 的迭代器返回这些元素的顺序(可选操作)。 |
boolean addAll(int index, Collection<? extends E> c) | 将指定 collection 中的所有元素都插入到列表中的指定位置(可选操作)。 |
void clear() | 从列表中移除所有元素(可选操作)。 |
boolean contains(Object o) | 如果列表包含指定的元素,则返回 true。 |
boolean containsAll(Collection<?> c) | 如果列表包含指定 collection 的所有元素,则返回 true。 |
boolean equals(Object o) | 比较指定的对象与列表是否相等。 |
E get(int index) | 返回列表中指定位置的元素。 |
int hashCode() | 返回列表的哈希码值。 |
int indexOf(Object o) | 返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。 |
boolean isEmpty() | 如果列表不包含元素,则返回 true。 |
Iterator iterator() | 返回按适当顺序在列表的元素上进行迭代的迭代器。 |
int lastIndexOf(Object o) | 返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1。 |
ListIterator listIterator() | 返回此列表元素的列表迭代器(按适当顺序)。 |
ListIterator listIterator(int index) | 返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。 |
E remove(int index) | 移除列表中指定位置的元素(可选操作)。 |
boolean remove(Object o) | 从此列表中移除第一次出现的指定元素(如果存在)(可选操作)。 |
boolean removeAll(Collection<?> c) | 从列表中移除指定 collection 中包含的其所有元素(可选操作)。 |
boolean retainAll(Collection<?> c) | 仅在列表中保留指定 collection 中所包含的元素(可选操作)。 |
E set(int index, E element) | 用指定元素替换列表中指定位置的元素(可选操作)。 |
int size() | 返回列表中的元素数。 |
List subList(int fromIndex, int toIndex) | 返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。 |
Object[] toArray() | 返回按适当顺序包含列表中的所有元素的数组(从第一个元素到最后一个元素)。 |
T[] toArray(T[] a) | 返回按适当顺序(从第一个元素到最后一个元素)包含列表中所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。 |
- ListIterator具有的方法
用法 | 解释 |
---|---|
void add(E e) | 将指定的元素插入列表(可选操作)。 |
boolean hasNext() | 以正向遍历列表时,如果列表迭代器有多个元素,则返回 true(换句话说,如果 next 返回一个元素而不是抛出异常,则返回 true)。 |
boolean hasPrevious() | 如果以逆向遍历列表,列表迭代器有多个元素,则返回 true。 |
E next() | 返回列表中的下一个元素。 |
int nextIndex() | 返回对 next 的后续调用所返回元素的索引。 |
E previous() | 返回列表中的前一个元素。 |
int previousIndex() | 返回对 previous 的后续调用所返回元素的索引。 |
void remove() | 从列表中移除由 next 或 previous 返回的最后一个元素(可选操作)。 |
void set(E e) | 用指定元素替换 next 或 previous 返回的最后一个元素(可选操作)。 |
- List接口实例
public static void main(String[] args) {
List list = new ArrayList();
//1.添加元素
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
System.out.println("元素个数"+list.size());
System.out.println(list.toString());
//2.删除元素
list.remove("aaa");
//list可以通过下标删除
list.remove(0);
System.out.println("元素个数"+list.size());
System.out.println(list.toString());
//list.clear();
//3.遍历
//3.1使用for循环
for (int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
//3.2使用增强for
for (Object object:list
) {
System.out.println(object);
}
//3.3使用迭代器Iterator
Iterator iterator =list.iterator();
while (iterator.hasNext()){
System.out.println( iterator.next());
}
//3.4使用ListIterator
ListIterator listIterator = list.listIterator();
//ListIterator从前往后输出
while (listIterator.hasNext()){
System.out.println(listIterator.nextIndex()+":"+listIterator.next());
}
//ListIterator从后往前输出,这个如果指针指向的是第一个元素就没有用了
//hasPrevious判断的是有没有前一个元素,这里之所以能直接输出是因为前面用了hasNext,已经将指针指向了最后一位
while (listIterator.hasPrevious()){
System.out.println(listIterator.previousIndex()+":"+listIterator.previous());
}
//4.判断
System.out.println(list.contains("ccc"));
System.out.println(list.isEmpty());
//5.获取位置下标
System.out.println(list.indexOf("ddd"));
}
- List接口实现类
ArrayList:
- 数组结构实现,查询快,增删慢
- JDK1.2版本,运行效率快,线程不安全
Vector:(了解就行)- 数组结构实现,查询快,增删慢
- JDK1.0版本,运行效率慢,线程安全
LinkedList:- 链表结构实现,查询慢,增删快
ArrayList
- ArrayList实现类的特点
数组,查找遍历速度快,增删慢
- ArrayList类的方法
用法 | 解释 |
---|---|
boolean add(E e) | 将指定的元素添加到此列表的尾部。 |
void add(int index, E element) | 将指定的元素插入此列表中的指定位置。 |
boolean addAll(Collection<? extends E> c) | 按照指定 collection 的迭代器所返回的元素顺序,将该 collection 中的所有元素添加到此列表的尾部。 |
boolean addAll(int index, Collection<? extends E> c) | 从指定的位置开始,将指定 collection 中的所有元素插入到此列表中。 |
void clear() | 移除此列表中的所有元素。 |
Object clone() | 返回此 ArrayList 实例的浅表副本。 |
boolean contains(Object o) | 如果此列表中包含指定的元素,则返回 true。 |
void ensureCapacity(int minCapacity) | 如有必要,增加此 ArrayList 实例的容量,以确保它至少能够容纳最小容量参数所指定的元素数。 |
E get(int index) | 返回此列表中指定位置上的元素。 |
int indexOf(Object o) | 返回此列表中首次出现的指定元素的索引,或如果此列表不包含元素,则返回 -1。 |
boolean isEmpty() | 如果此列表中没有元素,则返回 true |
int lastIndexOf(Object o) | 返回此列表中最后一次出现的指定元素的索引,或如果此列表不包含索引,则返回 -1。 |
E remove(int index) 移除此列表中指定位置上的元素。 | |
boolean remove(Object o) | 移除此列表中首次出现的指定元素(如果存在)。 |
protected void removeRange(int fromIndex, int toIndex) | 移除列表中索引在 fromIndex(包括)和 toIndex(不包括)之间的所有元素。 |
E set(int index, E element) | 用指定的元素替代此列表中指定位置上的元素。 |
int size() | 返回此列表中的元素数。 |
Object[] toArray() | 按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组。 |
T[] toArray(T[] a) | 按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。 |
void trimToSize() | 将此 ArrayList 实例的容量调整为列表的当前大小。 |
- ArrayListt的使用
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
//添加元素
Student s1=new Student("张三",1);
Student s2=new Student("李四",2);
Student s3=new Student("王五",3);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
System.out.println("元素个数"+arrayList.size());
System.out.println(arrayList.toString());
//删除元素
arrayList.remove(new Student("张三",1));//调用equals方法比较,
// 因为Object中的equals方法是比较前后两个的地址是否相同,
// 所有我们在子类Student中重写父类Object的equals方法
//1.判断是否为同一个对象2.判断是否为空3.判断是否为Student类型
//4.如果是Student类型,自行添加判断条件(这里是name和age必须一样)
System.out.println("元素个数"+arrayList.size());
System.out.println(arrayList.toString());
//3.遍历
//3.1使用迭代器Iterator
Iterator iterator =arrayList.iterator();
while (iterator.hasNext()){
System.out.println( iterator.next());
}
//3.2使用ListIterator
ListIterator listIterator = arrayList.listIterator();
//ListIterator从前往后输出
while (listIterator.hasNext()){
System.out.println(listIterator.nextIndex()+":"+listIterator.next());
}
//ListIterator从后往前输出,这个如果指针指向的是第一个元素就没有用了
//hasPrevious判断的是有没有前一个元素,这里之所以能直接输出是因为前面用了hasNext,已经将指针指向了最后一位
while (listIterator.hasPrevious()){
System.out.println(listIterator.previousIndex()+":"+listIterator.previous());
}
//4.判断
System.out.println(arrayList.contains(s1));
System.out.println(arrayList.contains(new Student("王五",3)));
System.out.println(arrayList.isEmpty());
//5.获取位置下标
System.out.println(arrayList.indexOf(s2));
}
Student类中重写的equals方法
@Override
public boolean equals(Object o) {
//this所指的是已经在集合中的对象
//因为我传的是new Student("张三",1)所以Object类0指向的是Student子类的对象
if (this == o) return true;
if (o == null ) return false;
//因为Object类0指向的是子类Student的对象,所以if为真
if(o instanceof Student) {
Student student = (Student) o;// Student student = new Student();
if (this.age == student.age && this.name.equals(student.name))
{
return true;
}
}
return false;
}
- ArrayList源码分析
几个常见的常量:
- 默认容量为10: DEFAULT_CAPACITY=10(这里如果我们没有向集合中添加任何元素则容量大小为0)
- 存放元素的数组 : elementData
- 实际的元素的个数: size
简单分析ArrayList中的add方法
总结:扩容就是当我添加第11个元素时,数组大小由10变为15,所以每次到数组大小峰值时就扩容为原来的1.5倍
public boolean add(E e) {
1.我们进入ensureCapacityInternal,当我添加第一个元素时size+1为1
18.当我添加第11个元素时就要进行扩容了,此时size+1为11,再进入ensureCapacityInternal
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
4.这里elementData数组为null,minCapacity为1
private static int calculateCapacity(Object[] elementData, int minCapacity) {
5.这里DEFAULTCAPACITY_EMPTY_ELEMENTDATA也为null
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
6.这里比较调用Math的max方法比较大小,DEFAULT_CAPACITY为10,minCapacity为1
所以返回10
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
20.返回11
return minCapacity;
}
19.minCapacity为11
2.当我添加第一个元素时size+1为1,所以minCapacity为1
private void ensureCapacityInternal(int minCapacity) {
3.这里elementData数组为null,minCapacity为1,我们先进入calculateCapacity
7.发现返回值为10,我们再进入ensureExplicitCapacity
21.这里返回11,我们再进入ensureExplicitCapacity
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
8.minCapacity为10
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
9.这里minCapacity 为10,elementData.length为0
22.minCapacity为11,elementData.length为10,因为里面有10个元素
if (minCapacity - elementData.length > 0)
23.进入grow方法
10.所以我们进入grow方法
grow(minCapacity);
}
11此时进入grow方法minCapacity为10
private void grow(int minCapacity) {
// overflow-conscious code
24.这个elementData.length为10,所以oldCapacity为10
12.这个elementData.length为0,所以oldCapacity为0
int oldCapacity = elementData.length;
25.oldCapacity + (oldCapacity >> 1)为 10+10右移一位(右移一位相当于除以2)结果为15,所以newCapacity 为15
13.oldCapacity + (oldCapacity >> 1)为 0+0右移一位结果还是0,所以newCapacity 为0
int newCapacity = oldCapacity + (oldCapacity >> 1);
26.newCapacity - minCapacity为15-10,所以大于0
14.newCapacity - minCapacity为0-10,所以小于0
if (newCapacity - minCapacity < 0)
15.所以newCapacity =10
newCapacity = minCapacity;
16.( MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;)所以MAX_ARRAY_SIZE很大,if基本不成立
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
17.使用数组的copyOf,创建了一个大小为10的数组elementData
27.此时elementData为10,newCapacity为15,所以创建了大小为15的数组elementData
elementData = Arrays.copyOf(elementData, newCapacity);
}
LinkedList
- LinkedList的特点:
- 双向链表结构实现,查询慢,增删快
- LinkedList类的方法
用法 | 解释 |
---|---|
boolean add(E e) | 将指定元素添加到此列表的结尾 |
void add(int index, E element) | 在此列表中指定的位置插入指定的元素。 |
boolean addAll(Collection<? extends E> c) | 添加指定 collection 中的所有元素到此列表的结尾,顺序是指定 collection 的迭代器返回这些元素的顺序。 |
boolean addAll(int index, Collection<? extends E> c) | 将指定 collection 中的所有元素从指定位置开始插入此列表。 |
void addFirst(E e) | 将指定元素插入此列表的开头。 |
void addLast(E e) | 将指定元素添加到此列表的结尾。 |
void clear() | 从此列表中移除所有元素。 |
Object clone() | 返回此 LinkedList 的浅表副本。 |
boolean contains(Object o) | 如果此列表包含指定元素,则返回 true。 |
Iterator descendingIterator() | 返回以逆向顺序在此双端队列的元素上进行迭代的迭代器。 |
E element() | 获取但不移除此列表的头(第一个元素)。 |
E get(int index) | 返回此列表中指定位置处的元素。 |
E getFirst() | 返回此列表的第一个元素。 |
E getLast() | 返回此列表的最后一个元素。 |
int indexOf(Object o) | 返回此列表中首次出现的指定元素的索引,如果此列表中不包含该元素,则返回 -1。 |
int lastIndexOf(Object o) | 返回此列表中最后出现的指定元素的索引,如果此列表中不包含该元素,则返回 -1。 |
ListIterator listIterator(int index) | 返回此列表中的元素的列表迭代器(按适当顺序),从列表中指定位置开始。 |
boolean offer(E e) | 将指定元素添加到此列表的末尾(最后一个元素)。 |
boolean offerFirst(E e) | 在此列表的开头插入指定的元素。 |
boolean offerLast(E e) | 在此列表末尾插入指定的元素。 |
E peek() | 获取但不移除此列表的头(第一个元素)。 |
E peekFirst() | 获取但不移除此列表的第一个元素;如果此列表为空,则返回 null。 |
E peekLast() | 获取但不移除此列表的最后一个元素;如果此列表为空,则返回 null。 |
E poll() | 获取并移除此列表的头(第一个元素) |
E pollFirst() | 获取并移除此列表的第一个元素;如果此列表为空,则返回 null。 |
E pollLast() | 获取并移除此列表的最后一个元素;如果此列表为空,则返回 null。 |
E pop() | 从此列表所表示的堆栈处弹出一个元素。 |
void push(E e) | 将元素推入此列表所表示的堆栈。 |
E remove() | 获取并移除此列表的头(第一个元素)。 |
E remove(int index) | 移除此列表中指定位置处的元素。 |
boolean remove(Object o) | 从此列表中移除首次出现的指定元素(如果存在)。 |
E removeFirst() | 移除并返回此列表的第一个元素。 |
boolean removeFirstOccurrence(Object o) | 从此列表中移除第一次出现的指定元素(从头部到尾部遍历列表时)。 |
E removeLast() | 移除并返回此列表的最后一个元素。 |
boolean removeLastOccurrence(Object o) | 从此列表中移除最后一次出现的指定元素(从头部到尾部遍历列表时)。 |
E set(int index, E element) | 将此列表中指定位置的元素替换为指定的元素。 |
int size() | 返回此列表的元素数。 |
Object[] toArray() | 返回以适当顺序(从第一个元素到最后一个元素)包含此列表中所有元素的数组。 |
T[] toArray(T[] a) | 返回以适当顺序(从第一个元素到最后一个元素)包含此列表中所有元素的数组;返回数组的运行时类型为指定数组的类型。 |
- LinkedList的使用
public static void main(String[] args) {
//添加元素
LinkedList linkedList = new LinkedList();
Student s1 =new Student("aaa",15);
Student s2 =new Student("bbb",16);
Student s3 =new Student("ccc",17);
Student s4 =new Student("ccc",17);
linkedList.add(s1);
linkedList.add(s2);
linkedList.add(s3);
linkedList.add(s4);
System.out.println("元素个数"+linkedList.size());
System.out.println(linkedList.toString());
//删除元素
linkedList.remove(s3);
System.out.println("删除之后"+linkedList.size());
System.out.println(linkedList.toString());
//遍历
//3.1 使用迭代器遍历
Iterator iterator = linkedList.iterator();
while(iterator.hasNext())
{
Object o=iterator.next();
System.out.println(o);
}
//3.2使用ListIterator
ListIterator listIterator = linkedList.listIterator();
while(listIterator.hasNext()){
Object o2=listIterator.next();
System.out.println(listIterator.nextIndex()+":"+o2);
}
while (listIterator.hasPrevious()){
System.out.println(listIterator.previousIndex()+":"+listIterator.previous());
}
//判断
System.out.println(linkedList.contains(s2));
System.out.println(linkedList.isEmpty());
//获取下标
System.out.println(linkedList.indexOf(s1));
}
- LinkedList源码分析
三个属性
transient int size = 0;大小
transient Node first;头节点
transient Node last;尾节点
add源码分析
1.进入add方法
public boolean add(E e) {
2.进入linklast方法
linkLast(e);
return true;
}
void linkLast(E e) {
3.进入Node方法
5.l指向last,l和last都为空
11.当我们添加第二个节点,第7.中l指向的是第一个节点,所以l指向第一个节点
final Node<E> l = last;
6.创建一个newNode节点,l指向prev为空,元素e,next为null
12.创建第二个节点,l传给prev,l指向第一个节点,就是prev指向l,所以第二个节点指向第一个节点
final Node<E> newNode = new Node<>(l, e, null);
7.last指向newNode
13.last指向第二个节点
last = newNode;
8.l指向last,last为空,l为空
14.此时l指向的是第一个节点,有元素e不为空
if (l == null)
9.first指向第一个节点
first = newNode;
else
15.l的下一个指向第二个节点,所以就是第一个节点指向第二个节点
l.next = newNode;
10. size+1
size++;
modCount++;
}
private static class Node<E> {
E item; //元素
Node<E> next; //下一个
Node<E> prev; //前一个
4.Node方法传参第一个是prev,第二个是element,第三个是next
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
ArrayList和LinkedList的区别
ArrayList:必须开辟连续的空间,查询快,增删慢。
LinkedList:无需开辟连续空间,双向链表结构,查询慢,增删快。