目录
一.集合概述
我们经常需要存储一些数据类型相同的元素,之前我们学过的容器就是数组,但是数组存在一个问题
1.数组的长度一旦确定就不能改变
但是我们在实际开发中,往往需要动态增长的容器来帮我们存储数据,显然只用数组的话需要自己去创建新数组并拷贝元素,这大大降低了开发效率,所以java提供了底层不同实现的数据结构的容器称为集合
二. 集合体系概述
1. Collection接口
Collection是一个接口,里面可以定义抽象方法,常量,静态方法,默认方法(jdk8及之后),该接口是单列集合的父接口,其中主要用于定义一些单列集合通用的方法,例如:单列集合的增删改查
1.1 List接口
List接口继承了Collection接口,List接口下的实现类允许出现重复元素,可以用索引和迭代器访问,主要有ArrayList,LinkedList,Vector等实现类
1.2 Set接口
Set接口同样继承了Collection接口,Set接口下的实现类不允许出现重复元素,且不能用索引访问,只能用迭代器访问,主要有HashSet,TreeSet等实现类
2. Map接口
Map是一个接口,里面可以定义抽象方法,常量,静态方法,默认方法(jdk8及之后),该接口是双列(键值对存储)集合的父接口,其中主要定义一些双列集合通用的方法,例如:双列集合的增删改查,主要有HashMap等实现类
三. List接口下的实现类
1.ArrayList
ArrayList是List接口下的一个实现类,底层是一个可以动态增长的数组,所有的集合容器中都可以添加任意类型的数据,但为了使用时的统一,用一个<>指明集合中的元素类型,这是泛型,例如:<String>
1.1 ArrayList常用方法
size() | 返回集合中实际元素个数 |
add(E e) | 向集合末尾添加元素,添加成功返回true,添加失败返回false |
add(int index,E e) | 向指定位置处添加元素 |
remove(Object o) | 删除指定内容的元素,删除成功返回true,删除失败返回false |
remove(int index) | 删除指定位置处的元素,删除成功会把该值返回 |
get(int index) | 获取指定位置处的元素 |
indexOf(Object o) | 从左向右查找指定元素,找到返回下标,找不到返回-1 |
lastIndexOf(Object o) | 从右向左查找指定元素,找到返回下标,找不到返回-1 |
set(int index,E element) | 用指定的元素替换指定位置的元素,同时返回旧元素 |
isEmpty() | 判断集合是否为空 |
contains(Object o) | 判断集合中是否包含指定元素 |
2. LinkedList
LinkedList是List接口下的一个实现类,底层是链表结构,LinkedList一般用来模拟栈和队列很方便
2.1 LinkedList常用方法
int size() | 返回集合中的元素个数 |
boolean add(E e) | 向集合尾部添加指定元素,添加成功返回true,添加失败返回false |
void add(int index,E element() | 向指定位置添加指定元素 |
E get(int index) | 获取指定位置的元素 |
boolean remove(Object o) | 删除指定元素,删除成功返回true,删除失败返回false |
E remove(int index) | 删除指定位置的元素,并将其返回 |
E remove() | 删除头部的元素并返回 |
void addFirst(E e) | 向头部添加元素 |
E removeLast() | 删除尾部元素并返回 |
void addLast(E e) | 向尾部添加元素 |
E pop() | 删除头部元素并返回 |
void clear() | 清空链表元素 |
boolean isEmpty() | 判断链表是否为空 |
boolean contains(Object o) | 判断链表中是否包含指定元素 |
3. Vector
vector和ArrayList底层都是数组,且两者所拥有的方法也都是相同的,唯一的不同是,Vector的方法中被synchronized修饰,是线程安全的,它们两者的关系就好像StringBuffer和StringBuilder的关系一样
4. List接口下的实现类的遍历
这里以ArrayList为例,LinkedList和vector也是类似的
1. for循环
public class ArrayListDemo4 {
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("a");
arrayList.add("a");
arrayList.add("a");
arrayList.add("b");
arrayList.add("c");
arrayList.add("d");
for(int i = 0;i < arrayList.size(); i++){
if("a".equals(arrayList.get(i))){
arrayList.remove("a");
i--;
}
}
}
}
注意:用for循环删除集合中的元素时要注意索引和元素位置的变化,将索引减回去,避免删除元素不彻底
2. 增强for循环
public class ArrayListDemo4 {
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("a");
arrayList.add("a");
arrayList.add("a");
arrayList.add("b");
arrayList.add("c");
arrayList.add("d");
/*
2.增强for循环
增强for循环遍历元素时,不允许修改集合元素(删除,添加)
*/
for(String s:arrayList){
//arrayList.remove(s);
System.out.print(s+" ");
//arrayList.add("1");
}
}
}
注意:在使用增强for循环遍历集合时不能对集合进行增删改查等操作
3. 迭代器遍历
public class ArrayListDemo4 {
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("a");
arrayList.add("a");
arrayList.add("a");
arrayList.add("b");
arrayList.add("c");
arrayList.add("d");
/*
迭代器遍历
*/
//获得集合对象的迭代器对象
Iterator<String> it = arrayList.iterator();
//正向遍历
while(it.hasNext()) {
String s = it.next();//获取到下一个元素
System.out.print(s+" ");
/*if(s.equals("b")){
it.remove();//使用迭代器对象删除元素
}*/
}
System.out.println();
//ListIterator 迭代器 只能对List接口下的实现类遍历
//listIterator(index);可以从指定的位置开始向前或者向后遍历
ListIterator<String> listIterator = arrayList.listIterator(1);
while(listIterator.hasNext()){
System.out.print(listIterator.next()+" ");
}
System.out.println();
//反向遍历
ListIterator<String> listIterator1 = arrayList.listIterator(arrayList.size());
while(listIterator1.hasPrevious()){
System.out.print(listIterator1.previous()+" ");
}
}
}
使用迭代器遍历集合是更推荐的方法,它既可以在遍历时对集合进行操作,也不用自己去管下一个元素是否会被略过
四.Set接口下的实现类
1.HashSet
HashSet是Set接口下的实现类,Set接口不允许出现重复元素,HashSet元素是无序的(不是按照添加顺序存储),HashSet其实就是对HashMap的键进行了包装,去掉了值的部分,形成的单列集合
1.1 HashSet常用方法
boolean add(E e) | 向Set集合中添加指定元素,添加成功返回true,添加失败返回false |
boolean remove(Object o) | 删除指定元素,删除成功返回true,删除失败返回false |
boolean contains(Object o) | 判断是否包含指定元素,包含返回true,不包含返回false |
void clear() | 清空集合中的元素 |
boolean isEmpty() | 判断集合是否为空,为空返回true,不为空返回false |
int size() | 返回集合中的实际元素个数 |
iterator() | 获取遍历集合的迭代器 |
1.2 HashSet判断重复元素机制
我们说Set是不能够存储重复元素的,那么HashSet如何判断重复元素呢,我们想到的就是调用重写的equals()方法,但是在equals()方法中它是一个一个去比较效率非常低,所以为了解决这个问题,实际的HashSet会先调用类中重写的hashCode()方法,对于两个相同的元素他们的hashCode()值计算出来一定是相同的,则直接不会被添加到HashSet中,但对于两个元素值不相同,有可能计算出来的hashCode()值是相同的,此时会再去调用equals()方法一个一个比较内容是否相同,这样就大大减少了调用equals()方法的次数,既提高了效率又增强了安全性
2. TreeSet
TreeSet中的元素是可以排序的,即Set集合虽是无序的,但由于TreeSet底层是一颗二叉搜索树,所以在向TreeSet中添加元素时该元素的类型必须实现Comparable接口中的compareTo()方法
1.1 TreeSet常用方法
boolean add(E e) | 向Set集合中添加指定元素,添加成功返回true,添加失败返回false |
boolean contains(Object o) | 判断是否包含指定元素,包含返回true,不包含返回false |
void clear() | 清空集合中的元素 |
boolean isEmpty() | 判断集合是否为空,为空返回true,不为空返回false |
int size() | 返回集合中的实际元素个数 |
iterator() | 获取遍历集合的迭代器 |
E first() | 返回第一个元素,根节点的值 |
E last() | 返回最后一个元素 |
1.2 TreeSet判断重复元素机制
因为其底层是一颗二叉搜索树且使用TreeSet的类都实现了Comparable接口中的compareTo()方法,所以在向TreeSet中添加元素时,会进行判断如果比当前节点小就会去左子树继续比较,如果比当前节点大就会去右子树继续比较直到为空后插入,如果相等则是重复元素不会插入到树中