Java容器总结
文章总结自博客: https://blog.csdn.net/zhangqunshuai/article/details/80660974
概述
- List、Set、Map都是接口,前两个继承至Collection接口,Map为独立接口
- Set下有
HashSet
、LinkedHashSet
、TreeSet
- List下有
ArrayList
、Vector
、LinkedList
- Map下有
HashTable
、LinkedHashMap
、HashMap
、TreeMap
- Collection接口下还有个
Queue接口
,有PriorityQueue类
Collection接口下面有三个接口List、Set、Queue
LinkedList
既可以实现Queue接口,也可以实现List接口,但是当LinkedList
实现Queue接口
,Queue接口
窄化了对LinkedList
的方法的访问权限(即在方法中的参数类型如果是Queue
时,就完全只能访问Queue接口
所定义的方法了,而不是能直接访问LinkedList
的非Queue的方法),以使得只有恰当的方法才可以使用SortedSet
是个接口,它里面的(只有TreeSet
这一个实现可用)中的元素一定是有序的
📚Collection
📒List
有序,可重复
📃ArrayList
优点:底层数据结构是数组,查询快,增删慢
缺点:线程不安全,效率高
📃Vector
优点:底层数据结构是数组,查询快,增删慢
缺点:线程安全,效率低
📃LinkedList
优点:底层数据结构是链表,查询慢,增删快
缺点:线程不安全,效率高
📒Set
无序,唯一
📃HashSet
底层数据结构是哈希表(无序,唯一)
如何保证元素唯一性?
1.依赖两个方法:hashCode()
和equals()
📃LinkedHashSet
底层数据结构是链表和哈希表(有序,唯一)
- 由链表保证元素有序
- 由哈希表保证元素唯一
📃TreeSet
底层数据结构是红黑树(有序,唯一)
1.如何保证元素排序的呢?
- 自然排序
- 比较器排序
2.如何保证元素的唯一性的呢?
根据比较的返回值是否为0来决定
📃总结
TreeSet
的主要功能用于排序LinkedHashSet
的主要功能用于保证FIFO即有序的集合(先进先出)HashSet
只是通用的存储数据的集合
📒使用场景
📃唯一:Set
- 排序:
TreeSet
或LinkedHashSet
- 不排:
HashSet
- 知道是
Set
,但是不知道是哪个,就用HashSet
📃不唯一:List
- 安全:Vector
- 不安全:
ArrayList
或LinkedList
- 查询多:
ArrayList
- 增删多:
LinkedList
- 如果知道是
List
,但是不知道是哪个List
,就用ArrayList
- 查询多:
📚Map
Map接口有三个比较重要的实现类,分别是HashMap
、TreeMap
、HashTable
TreeMap
是有序的,HashMap
和HashTable
是无序的HashTable
的方法是同步的,HashMap
的方法不是同步的
这就意味着
HashTable
是线程安全的,HashMap
不是线程安全的HashMap
效率高,Has和Table
效率较低- 如果对同步性或与遗留代码的兼容性没有任何要求,建议使用
HashMap
。 查看Hashtable
的源代码就可以发现,除构造函数外,Hashtable
的所有 public 方法声明中都有synchronized
关键字,而HashMap
的源码中则没有
- 如果对同步性或与遗留代码的兼容性没有任何要求,建议使用
HashTable
不允许null值,HashMap
允许null值(key和value都允许)- 父类不同:
HashTable
的父类是Dictionary
,HashMap
的父类是AbstractMap
========================
Collection
Collection集合中通用的功能
Collection集合常用符方法
方法名 | 说明 |
---|---|
boolean add(E e) | 添加元素 |
boolean remove(Object o) | 从集合中移除指定的元素 |
void clear() | 清空集合中的元素 |
boolean contains(Object o) | 判断集合中是否存在指定的元素 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度 |
package com.study_01;
import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo02 {
public static void main(String[] args) {
// 通过多态的方法创建对象
Collection<String> c = new ArrayList<>();
// add方法永远返回true
// System.out.println(c.add("hello")); // true
c.add("hello");
c.add("java");
c.add("world");
// 删除元素:boolean remove(Object o)
// System.out.println(c.remove("world")); // true
// System.out.println(c.remove("javaee")); // false
// 清除集合中的元素:void clear()
// c.clear();
// 判断集合中是否存在指定的元素:boolean contains(Object o)
// System.out.println(c.contains("world")); // true
// System.out.println(c.contains("javaee")); // false
System.out.println(c.isEmpty()); // 判断集合是否为空
System.out.println(c.size()); // 集合的长度
System.out.println(c);
}
}
Collection集合的遍历
**lterator**
:迭代器,集合的专用遍历方式
存在并发修改异常
Iterator iterator
:返回此集合中元素的迭代器,通过集合的iterator()
方法得到- 迭代器是通过集合的
iterator()
方法得到的,所以我们说它是依赖于集合而存在的
**lterator**
中的常用方法
E next()
:返回迭代中的下一个元素boolean hasNext()
:如果迭代具有更多元素,则返回true
增强for循环:简化数组和Collection集合的遍历
- 实现
lterable接口
的类允许其对象成为增强型for语句的目标 - 它是JDK5之后出现的,其内部原理是一个
lterator迭代器
for(元素数据类型 变量名:数组或者Collection集合){
//在此处使用变量即可,该变量就是元素
}
int[] arr = {1,2,3,4,5};
// 内部其实是个Iterable迭代器
for (int i :arr) {
System.out.println(i);
}
package com.study_02;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class IteratorDemo {
public static void main(String[] args) {
// 创建Collection集合对象 多态
Collection<String> c = new ArrayList<>();
// 添加元素:boolean add(E e)
c.add("hello");
c.add("world");
c.add("java");
// Iterator<E> iterator() 返回此集合中元素的迭代器 通过集合的iterator()方法得到
Iterator<String> it = c.iterator();
/* ----Iterator<E> iterator()-----
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
...
}
*/
// 用while循环改进判断
// boolean hasNext():如果迭代具有更多元素,则返回true
while (it.hasNext()) {
// E next():返回迭代中的下一个元素
String s = it.next();
System.out.println( s);
}
}
}
List集合特有的功能
List集合特有方法
方法名 | 说明 |
---|---|
void add(String item, int index) | 在此集合指定位置插入指定的元素 |
E remove(int index) | 删除指定索引出的元素,返回别删除的元素 |
E set(int index,E element) | 修改指定索引出的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
package com.study_01;
import java.util.ArrayList;
import java.util.List;
public class ListDemo02 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
// 添加元素:boolean add(E e)
list.add("hello");
list.add("world");
list.add("java");
// 在此集合指定位置插入指定的元素:void add(String item, int index)
// list.add(1,"javaEE");
// list.add(11,"javaEE"); // IndexOutOfBoundsException 索引越界异常
// 删除指定索引处的元素,返回别删除的元素:E remove(int index)
// System.out.println(list.remove(1)); // world
// System.out.println(list.remove(11)); // IndexOutOfBoundsException 索引越界异常
// 修改指定索引处的元素,返回被修改的元素:Eset(Int index,E element)
// System.out.println(list.set(1,"javaEE")); // world
// System.out.println(list.set(11,"javaEE")); // IndexOutOfBoundsException 索引越界异常
// 返回指定索引处的元素:E get(int index)
// System.out.println(list.get(1)); // world
// System.out.println(list.get(11)); // IndexOutOfBoundsException 索引越界异常
// System.out.println(list);
for (int i = 0; i < list.size(); i++) {
// E next():返回迭代中的下一个元素
String s = list.get(i);
System.out.println(s);
} 34m
}
}
ListIterator列表迭代器
**Iterator**
会引发的问题
并发修改异常:ConcurrentModificationException
产生原因:迭代器遍历的过程中,通过集合对象修改了集合中元素的长度,造成了迭代器获取元素中判断预期修改值和实际修改值不一致‘’
**ListIterator**
列表迭代器
- 通过List集合的listlterator()方法得到,所以说它是List集合特有的迭代器
- 用于允许程序员沿任一方向遍历列表的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置
**ListIterator**
中常用的方法
方法名 | 说明 |
---|---|
E next() | 返回迭代中的下一个元素 |
boolean hasNext() | 如果迭代具有更多元素,则返回true |
E previous() | 返回列表中的上一个元素 |
boolean hasPrevious() | 如果此列表迭代器在相反方向遍历列表时具有更多的元素,则返回true |
void add(E e) | 将指定的元素插入列表 |
package com.study_04;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class ListIteratorDemo {
public static void main(String[] args) {
// 创建一个集合对象
List<String> list = new ArrayList<>();
// 添加元素:boolean add(E e)
list.add("hello");
list.add("world");
list.add("java");
// 正向迭代
// ListIterator<String> lit = list.listIterator();
// while (lit.hasNext()){
// String s = lit.next();
// System.out.println(s);
// }
// System.out.println("--------------");
// 反向迭代 此时lit指向尾部
// while (lit.hasPrevious()){
// String s = lit.previous();
// System.out.println(s);
// }
// 获取列表迭代器
ListIterator<String> lit = list.listIterator();
while (lit.hasNext()){
String s = lit.next();
// 在迭代期间修改列表,并获取列表中迭代器的当前位置
if (s.equals("world")) {
lit.add("javase");
}
}
System.out.println(list);
}
}
LinkedLsit集合特有功能
方法名 | 说明 |
---|---|
public void addFirst(Ee) | 在该列表开头插入指定的元素 |
public void addLast(Ee) | 将指定的元素追加到此列表的末尾 |
public E getFirst() | 返回此列表中的第一个元素 |
public E getLast() | 返回此列表中的最后一个元素 |
public E removeFirst() | 从此列表中删除并返回第一个元素 |
public E removeLast() | 从此列表中删除并返回最后一个元素 |
package com.study_09;
import java.util.LinkedList;
public class LinkedListDemo {
public static void main(String[] args) {
// 创建一个集合对象
LinkedList<String> linkedList = new LinkedList<>();
linkedList.add("hello");
linkedList.add("world");
linkedList.add("java");
// [hello, world, java]
// public void addFirst(Ee):在该列表开头插入指定的元素
// public void addLast(Ee):将指定的元素追加到此列表的末尾
// linkedList.addFirst("javaSe");
// linkedList.addLast("javase");
// publicE getFirst():返回此列表中的第一个元素
// public E getLast():返回此列表中的最后一个元素
// System.out.println(linkedList.getFirst());
// System.out.println(linkedList.getLast());
// public E removeFirst():从此列表中删除并返回第一个元素
// public E removeLast():| 从此列表中删除并返回最后一个元素 |
System.out.println(linkedList.removeFirst());
System.out.println(linkedList.removeLast());
System.out.println(linkedList);
}
}
Set集合
Set集合特点
- 不包含重复元素的集合
- 没有带索引的方法,所以不能使用普通for循环遍历
哈希值
哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
Object类中有一个方法可以获取对象的哈希值
public int hashCode()
:返回对象的哈希码值
对象的哈希值特点
- 同一个对象多次调用hashCode()方法返回的哈希值是相同的
- 默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同
HashSet集合特点
- 底层数据结构是哈希表
- 对集合的迭代顺序不做任何保证,也就是说不保证存储和取出的元素顺序一致
- 没有带索引的方法,所以不能使用普遍for循环
- 由于是Set集合,所以是不包含重复元素的集合
package com.study_03;
import java.util.HashSet;
public class HashSetDemo {
public static void main(String[] args) {
// 创建集合对象
HashSet<String> hs = new HashSet<>();
// 添加元素
hs.add("hello");
hs.add("world");
hs.add("java");
hs.add("world");
// 遍历
for(String s : hs) {
System.out.println(s);
}
}
}
package com.study_02;
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int hashCode() {
// return super.hashCode();
return Objects.hash(name, age); // 重写hashCode方法
}
}