目录
一、集合概述
-
集合框架(java.util)的由来:容器类(集合类)可以存储多个数据,数组明明可以存储多个数据,为啥还要定义容器类?
-
数组弊端:
-
长度一但固定就不可变
-
很多地方需要操作数组的(增删改查)都需要去编写对应的方法(代码重复了--->封装)
-
每个人定义各自的方法,可能存在别人找不到 这种情况,实现也容易存在bug
-
-
-
什么是集合框架:容器类确实很好用,集合框架框架是为了提供一些规范和标准,任何实现类都需要包含对外的接口,接口的实现,对集合内部的算法(底层都是一种数据结构)
-
定义集合框架的目的:提供代码复用(封装的思想),让使用者专注于业务开发,而不是数据结构和算法。
-
常见集合类:
-
List(列表):集合中对象按照索引位置排序,允许元素重复。
-
Set(集):集合中的元素不按特定方式排序,不允许元素重复。
-
Map(映射):集合中的元素(key-value),不允许key 重复,值可以重复。
-
二、Collection 常用方法
-
接口定义的常用方法规范
//集合容量大小 int size(); //判断集合是否为空 boolean isEmpty(); //包含是否有某一个元素 boolean contains(Object o); //迭代器 Iterator<E> iterator(); //转换成数组 Object[] toArray(); //添加元素的 boolean add(E e); //删除元素 boolean remove(Object o); //判断集合是否包含另一个集合 boolean containsAll(Collection<?> c); //添加一个集合 boolean addAll(Collection<? extends E> c); //清空 void clear(); //获取hashcode int hashCode();
-
通用迭代
Iterator it = 集合对象.iterator(); while(it.hasNext()){ Object ele = it.next(); } //迭代器接口 //判断是否有下一个元素 boolean hasNext(); //获取下一个元素 E next();
三、List 接口
-
List 接口规范:
//根据索引获取元素值 E get(int index); //设置某一个索引位置元素值 E set(int index, E element); //删除某一个索引位置的值 E remove(int index); //截取 List<E> subList(int fromIndex, int toIndex);
四、Vector 实现类
-
看源码学习
public class Vector<E> extends AbstractList<E> implements List<E>{ //元素数组 protected Object[] elementData; //元素个数 protected int elementCount; //扩容容量 protected int capacityIncrement; public Vector(int initialCapacity, int capacityIncrement) { this.elementData = new Object[initialCapacity]; this.capacityIncrement = capacityIncrement; } public Vector(int initialCapacity) { this(initialCapacity, 0); } public Vector() { this(10); } public synchronized void addElement(E obj) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = obj; } //扩容逻辑 private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; //如果你传进来扩容容量,新容量=老容量+传进来的扩容容量否则2倍老容量 int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) //给int类型的最大值 newCapacity = hugeCapacity(minCapacity); //数组的拷贝 elementData = Arrays.copyOf(elementData, newCapacity); } }
-
Vector 总结
-
底层使用 Object[] 数组(调用不带参数构造器时,默认长度为10,若不传扩容参数,扩容2倍)
-
toString 方法已经重写并且可以直接打印出数组的样子
-
增查删改
-
常用方法
-
add(E obj)
-
addElement(E obj)
-
-
查询
-
size() 查长度
-
get(int index) 查具体索引位置的元素值
-
isEmpty() 判断集合为空
-
-
删除
-
remove(int index)删除具体索引位置的元素
-
remove("A") 删除指定元素
-
removeLast() 循环,设置 null ,等待gc 回收
-
-
修改
-
set(int index,E obj);修改某一个索引位置元素值
-
-
五、Stack 栈
栈:是数据结构,First In Last Out
栈结构生活中的体现:
-
QQ消息:AB两个人先后发送消息,最后发送的是最新的。
栈:底层可以用数组,或者链表
//添加元素 public E push(E item) { addElement(item); return item; } //取元素并且删除 public synchronized E pop() { E obj; int len = size(); obj = peek(); removeElementAt(len - 1); return obj; } //查看栈顶元素 public synchronized E peek() { int len = size(); if (len == 0) throw new EmptyStackException(); return elementAt(len - 1); }
-
建议:建议使用ArrayDeque(方法会更加友好)
六、ArrayList
ArrayList 是用来取代 Vector.两者底层原理和算法,一模一样。
区别:
-
Vector:所有的方法都是用 synchronized 修饰符,表示线程安全的,性能低,适用于多线程环境
-
ArrayList:线程不安全,性能高,即使在多线程环境下也是用它(Collections.synchronizedList(list))
-
ArrayList 底层扩容是1.5倍,Vector 是两倍
-
底层构造器ArrayList 优化了,默认创建对象的时候是给一个空数组,第一次调用add 方法时,采取重新初始化数组(创建对象时,如果不存任何值,也浪费了堆空间)
七、LinkedList
-
LinkedList:是一个双向链表,双向队列(单向队列)list 的实现类。
Queue 方法 DQueue 方法 LinkedList boolean add(E e); void addFirst(E e); public E getFirst() E remove(); void addLast(E e); public E getLast() E poll(); E removeFirst(); public void addFirst(E e) E element(); E removeLast(); public void addLast(E e) E peek(); E pollFirst(); E pollLast(); E getFirst(); boolean add(E e); void push(E e); E pop(); -
面试题:请编写一个双向链表
-
注意:
-
LinkedList 是非线程安全的,保证线程安全,使用Collections 线程安全方法
-
擅长操作头和尾,大多数你以后要用的方法, addFirst addLast removeFirst
-
链表不存在索引,但是调用get(index) 是因为底层提供了 ListItr 这个内部类 提供了一个int 的索引
-
擅长保存和删除操作
-
八、List 的总结
-
根据 Vector ArrayList LinkedList 类的所有特点进行一个抽象,定义一个规范
-
特点:
-
允许元素重复
-
会记录添加顺序
-
具有很多共同方法
-
-
ArrayList 取代 Vector 直接使用
-
LinkedList:
-
数组结构的算法:插入和删除速度慢,查询和更改较快
-
链表结构的算法:插入和删除速度快,查询和更改较慢
-