一.集合体系框架
二.基本介绍
1.集合总体概述
集合是java中提供的一种容器,可以用来存储多个数据
长度可变;只能存储引用数据类型,即使存储了基本类型,到了集合中也会自动装箱成包装类;集合有很多方法,直接操作元素
2.分类(单列集合/双列集合)
单列集合:元素只由一部分构成
list.add("abc")
双列集合:一个元素由两部分构成,叫做键值对(key,value)
map.put(1,"zsy");
三.详细介绍
1.Collection接口
Collection接口是单列集合顶级接口
创建:Collection<E> 集合名 = new 实现类对象<E>()
是泛型,在这里先简单了解一下泛型的作用,后面会详细介绍,泛型是规定集合中元素的数据类型,统一类型的;泛型类型只能写引用类型,不能写基本类型,如果不写泛型,默认为Object类型
常用方法 | 方法作用 |
---|---|
.boolean add(E e) | 将给定的元素添加到当前集合中(一般调add时,不用boolean接收,因为add一定会成功) |
boolean addAll(Collection<? extends E> c) | 将另一个集合元素添加到当前集合中 (集合合并) |
void clear() | 清除集合中所有的元素 |
boolean contains(Object o) | 判断当前集合中是否包含指定的元素 |
boolean isEmpty() | 判断当前集合中是否有元素->判断集合是否为空 |
boolean remove(Object o) | 将指定的元素从集合中删除 |
int size() | 返回集合中的元素个数 |
Object[] toArray() | 把集合中的元素,存储到数组中 |
如下代码是方法使用的具体例子
public class Demo01 {
public static void main(String[] args) {
Collection<String> collection1 = new ArrayList<>();
//add(E e)将给定的元素添加到当前集合中
collection1.add("张三");
collection1.add("李四");
collection1.add("王五");
collection1.add("赵六");
collection1.add("刘七");
collection1.add("陈八");
System.out.println(collection1);
//addAll(Collection<? extends E> c)将另一个集合元素添加到当前集合中 (集合合并)
ArrayList<String> collection2 = new ArrayList<>();
collection2.addAll(collection1);
System.out.println(collection2);
//void clear():清除集合中所有的元素
collection2.clear();
System.out.println(collection2);
//boolean contains(Object o) :判断当前集合中是否包含指定的元素
boolean s = collection1.contains("赵六");
System.out.println(s);
//boolean isEmpty() : 判断当前集合中是否有元素->判断集合是否为空
boolean empty = collection1.isEmpty();
System.out.println(empty);
//boolean remove(Object o):将指定的元素从集合中删除
collection1.remove("陈八");
System.out.println(collection1);
//int size() :返回集合中的元素个数。
int size = collection1.size();
System.out.println(size);
//Object[] toArray(): 把集合中的元素,存储到数组中
Object[] arr = collection1.toArray();
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
2.List接口
List接口是Collection接口的子接口
2.1ArrayList集合
创建:ArrayList<泛型> 集合名 = new ArrayList<>()
特点
- 元素有序
- 元素可重复
- 有索引
- 线程不安全
- 数据结构:数组
常用方法 | 方法作用 |
---|---|
boolean add(E e) | 将元素添加到集合中->尾部(add方法一定能添加成功的,所以我们不用boolean接收返回值) |
void add(int index, E element) | 在指定索引位置上添加元素 |
boolean remove(Object o) | 删除指定的元素,删除成功为true,失败为false |
E remove(int index) | 删除指定索引位置上的元素,返回的是被删除的那个元素 |
E set(int index, E element) | 将指定索引位置上的元素,修改成后面的element元素 |
E get(int index) | 根据索引获取元素 |
int size() | 获取集合元素个数 |
如下代码是方法使用的具体例子
public class Demo01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
//boolean add(E e) -> 将元素添加到集合中->尾部(add方法一定能添加成功的,所以我们不用boolean接收返回值)
list.add("张三");
list.add("李四");
list.add("王五");
list.add("赵六");
list.add("田七");
System.out.println(list);
//void add(int index, E element) ->在指定索引位置上添加元素
list.add(0,"陈二");
System.out.println(list);
//boolean remove(Object o) ->删除指定的元素,删除成功为true,失败为false
//boolean result01 = list.remove("陈二");
//System.out.println("result01 = " + result01);
//System.out.println("list = " + list);
//E remove(int index) -> 删除指定索引位置上的元素,返回的是被删除的那个元素
boolean result = list.remove("陈二");
System.out.println("result = " + result);
System.out.println(list);
//E set(int index, E element) -> 将指定索引位置上的元素,修改成后面的element元素
list.set(0,"陈二");
System.out.println(list);
//E get(int index) -> 根据索引获取元素
String s = list.get(0);
System.out.println(s);
//int size() -> 获取集合元素个数
int size = list.size();
System.out.println(size);
}
}
2.1.1底层源码分析
ArrayList() -> 构造一个初始容量为 10 的空列表(数组)。
ArrayList(int initialCapacity) -> 构造一个具有指定初始容量的空列表。
在第一次add的时候ArrayList底层才会创建一个长度为10的空列表,ArrayList底层是数组,数组定长,数组扩容是由Arrays.copyof产生了个新数组System.arrayCopy(),每次扩容,扩容1.5倍
2.2LinkedList集合
List接口的实现类,方法和ArrayList一样
特点:
- 元素有序
- 有索引
- 元素可重复
- 线程不安全
- 数据结构:双向链表
特有方法:大量直接操作首尾元素的方法
特有方法 | 作用 |
---|---|
public void addFirst(E e) | 将指定元素插入此列表的开头。 |
public void addLast(E e) | 将指定元素添加到此列表的结尾。 |
public E getFirst() | 返回此列表的第一个元素。 |
public E getLast() | 返回此列表的最后一个元素。 |
public E removeFirst() | 移除并返回此列表的第一个元素。 |
public E removeLast() | 移除并返回此列表的最后一个元素。 |
public E pop() | 从此列表所表示的堆栈处弹出一个元素。 |
public void push(E e) | 将元素推入此列表所表示的堆栈。 |
public boolean isEmpty() | 如果列表不包含元素,则返回true。 |
如下代码是特有方法使用的具体例子
public class Demo01 {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<>();
list.add("张三");
//public void addFirst(E e):将指定元素插入此列表的开头。
list.addFirst("李四");
System.out.println("list = " + list);
//public void addLast(E e):将指定元素添加到此列表的结尾。
list.addLast("王五");
System.out.println("list = " + list);
//public E getFirst():返回此列表的第一个元素。
String first = list.getFirst();
System.out.println("first = " + first);
//public E getLast():返回此列表的最后一个元素。
String last = list.getLast();
System.out.println("last = " + last);
//public E removeFirst():移除并返回此列表的第一个元素。
String s = list.removeFirst();
System.out.println("s = " + s);
//public E removeLast():移除并返回此列表的最后一个元素。
String s1 = list.removeLast();
System.out.println("s1 = " + s1);
//public E pop():从此列表所表示的堆栈处弹出一个元素。
String pop = list.pop();
System.out.println("pop = " + pop);
//public void push(E e):将元素推入此列表所表示的堆栈。
list.push("赵六");
System.out.println("list = " + list);
//public boolean isEmpty():如果列表不包含元素,则返回true。
boolean empty = list.isEmpty();
System.out.println("empty = " + empty);
}
}
2.2.1LinkedList底层成员解释说明
1.LinkedList底层成员
transient int size = 0; 元素个数
transient Node first; 第一个节点对象
transient Node last; 最后一个节点对象
2.Node代表的是结点对象
private static class Node<E> {
E item;//节点上的元素
Node<E> next;//记录着下一个节点地址
Node<E> prev;//记录着上一个节点地址
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
2.2.2LinkedList中add方法源码分析(选看)
LinkedList<String> list = new LinkedList<>();
list.add("a");
list.add("b");
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
2.2.3LinkedList中get方法源码分析(选看)
index < (size >> 1)采用二分思想,先将index与长度size的一半比较,如果index<size/2,就只从位置0往后遍历到位置index处,而如果index>size/2,就只从位置size往前遍历到位置index处。这样可以减少一部分不必要的遍历
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
2.3Vector集合
Vector集合是List接口的实现类,从jdk1.0版本就有,到了jdk1.2时变成了List接口的实现类
特点:
- 有序
- 有索引
- 元素可重复
- 线程安全(效率不高)
- 数据结构:数组
无参构造创建Vector,底层数组初始容量为10,超过了10,自动扩容,扩2倍
3.Set接口
Set接口是Collection接口的子接口
Set接口并没有对Collection接口从方法上进行任何的扩
Set集合功能的实现,底层都是依靠Map集合去实现的
3.1HashSet集合的介绍和使用
HashSet是Set接口的一个实现类
特点:
-
元素唯一
-
无序(存的顺序和取的顺序不一样)
-
无索引
-
线程不安全
-
数据结构:哈希表
a.jdk8之前:哈希表 = 数组+链表
b.jdk8之后:哈希表 = 数组+链表+红黑树
加入红黑树目的:查询快好操作
方法和Collection一样
3.1.1HashSet的存储去重复的过程
1.先比较元素哈希值,再比较元素内容
2.如果哈希值不一样,内容肯定不一样,存
3.如果哈希值一样,再比较内容
如果哈希值一样,内容不一样,存
如果哈希值一样,内容也一样,去重复,后面的覆盖前面的
3.1.2HashSet存储自定义类型如何去重复
自定义对象中重写hashCode和equals方法
让set集合获取对象属性的哈希值,以及属性的内容进行比较
3.2LinkedHashSet的介绍以及使用
LinkedHashSet是Set接口的一个实现类
特点:
- 元素唯一
- 有序
- 无索引
- 线程不安全
- 数据结构:哈希表+链表
方法和Collection一样
3.3补充:哈希值
哈希值:计算机计算出来一个十进制数,可以看做是对象的地址值
获取:调用Object中的hashCode方法
如果哈希值一样,内容有可能不一样
如果哈希值不一样,内容一定不一样
如果一个对象中重写了hashCode方法,获取的就是对象内容的哈希值了
字符串的哈希值时如何算出来的
String s = "abc"
char[] value = {'a','b','c'}
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
第一次循环:
h = 31h+val[0] -> 31 0 + 97 = 97
第二次循环:
h = 31h+val[1] -> 3197+98 = 3105
第三次循环:
h = 31h+val[2] -> 313105+99 = 96354
31是一个质数,用31可以尽可能地降低内容不一样,哈希值一样的情况
3.3TreeSet集合
TreeSet 是 Set的实现类
特点:
- 对元素进行排序
- 元素唯一
- 无索引
- 线程不安全
- 数据结构:红黑树
使用:和HashSet一样
构造:
TreeSet()-> 构造一个新的空 set,该 set 根据其元素的自然顺序进行排序
4.Map集合
Map集合是双列集合顶级接口
key和value形式,键值对形式
key唯一,但是value可以重复
map.put("张三","李四");
map.put("王五","赵六");
map.put("张三","李四1"); -> 最后李四1会覆盖涛哥
4.1HashMap的介绍和使用
HashMap是Map的实现类
特点:
- key唯一,不能重复
- 无序
- 无索引
- 线程不安全
- 可以存储null键null值
- 数据结构:哈希表
常用方法 | 作用 |
---|---|
V put(K key, V value) | 添加元素 |
V remove(Object key) | 根据key删除键值对,返回的是被删除的value |
V get(Object key) | 根据key获取value |
boolean containsKey(Object key) | 判断集合中是否包含指定的key |
Collection values() | 获取结合中所有的value,转存到Collection集合中 |
Set keySet() | 将Map中的key获取出来,转存到Set集合中 |
Set<Map.Entry<K,V>> entrySet() | 获取Map集合中的键值对,转存到Set集合中 |
Map的key保证唯一和HashSet保证唯一的过程一样
4.2LinkedHashMap的介绍和使用
LinkedHashMap extends HashMap
特点:
- key唯一,不能重复
- 有序
- 无索引
- 线程不安全
- 可以存储null键null值
- 数据结构:哈希表+链表
使用:和HashMap一样
4.3HashMap的两种遍历方式
4.3.1获取key,根据key再获取value
Set keySet()->将Map中的key获取出来,转存到Set集合中
public class Demo01 {
public static void main(String[] args) {
HashMap<String, String> hashmap = new HashMap<>();
hashmap.put("张三","李四");
hashmap.put("王五","赵六");
Set<String> set = hashmap.keySet();
for (String s : set) {
String value = hashmap.get(s);
System.out.println("value = " + value);
}
}
}
4.3.2同时获取key和value
Set<Map.Entry<K,V>> entrySet()->获取Map集合中的键值对对象,转存到Set集合中
public class Demo02 {
public static void main(String[] args) {
HashMap<String, String> hashmap = new HashMap<>();
hashmap.put("张三","李四");
hashmap.put("王五","赵六");
Set<Map.Entry<String, String>> set = hashmap.entrySet();
for (Map.Entry<String, String> s : set) {
String key = s.getKey();
String value = s.getValue();
System.out.println(key+"..."+value);
}
}
}
4.4HashMap存储自定义对象如何保证key唯一
key必须重写hashCode和equals方法,比较key内容的哈希值以及key的内容
4.5TreeMap
TreeMap是Map的实现类
特点:
- 可以对key进行排序
- key唯一,value可重复
- 无索引
- 线程不安全
- 数据结构:红黑树
构造:
TreeMap() -> 对key进行自然排序
TreeMap(Comparator<? super K> comparator) -> 对key进行指定顺序排序
TreeMap<Person, String> treeMap1 = new TreeMap<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o2.getAge()-o1.getAge();
}
4.6Hashtable
Hashtable是Map集合的实现类,从jdk1.0版本就有,到了jdk1.2时变成了Map的实现类
特点:
- key唯一,value可重复
- 无序
- 无索引
- 线程安全
- 数据结构:哈希表
- 不能存储null键null值