目录
为什么要学习java集合?
为了保存数量不确定的数据,以及保存具有映射关系的数据(也被称为关联数组),Java 提供了集合类。集合类主要负责保存、盛装其他数据,因此集合类也被称为容器类。Java 所有的集合类都位于 java.util 包下,提供了一个表示和操作对象集合的统一构架,包含大量集合接口,以及这些接口的实现类和操作它们的算法。
集合类和数组不一样,数组元素既可以是基本类型的值,也可以是对象(实际上保存的是对象的引用变量),而集合里只能保存对象(实际上只是保存对象的引用变量,但通常习惯上认为集合里保存的是对象)。
Java 集合类型分为 Collection 和 Map,它们是 Java 集合的根接口,这两个接口又包含了一些子接口或实现类。图 1 和图 2 分别为 Collection 和 Map 的子接口及其实现类。
图 1 Collection接口基本结构
图 2 Map接口基本结构
一.list 集合
1.1list
- 特点:有序 且可重复
- 遍历:下标 迭代器
- 扩容:初始容量10,负载因子0.5,扩容增量0.5倍
- 新容量 = 原容量 + 原容量 * 0.5 , 如 ArrayList的容量为10,一次扩容后是容量为15
如何遍历:
下标
@Test//测试用力
public void test03() {
for (Integer integer : list) {
System.out.println(integer);
}
}
迭代器
@Test//测试用力
public void test04() {
Iterator<Integer> it=list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
1.2 Arraylist
- 简单数据结构,超出容量自动扩容,动态数组
- 内部实现是基于基础的对象数组的
- 随机访问快
- 不适合随机增加或删除
- 线程不安全
为什么不适合随机增加或删除?
运行这段代码的时候出现了一个报错
@Test
public void del() {
list.remove(1);
System.out.println(list);
}
报错结果
为什么?
程序发现那个位置也就是0位置那里并没有值,就会报这个错,也有人说是越界错误,也是可以理解的。数组越界了
解决方案:
@Test
public void del01() {
for (int i = 0; i < list.size(); i++) {
if(list.get(i)==3) {
list.remove(i);
}
}
System.out.println(list);
}
原始数据:
运行结果:
由此可以看出 删除了两个为3的元素
这就是为什么Arraylist 不适合删除的原因
但是可以推荐大家使用迭代器删除
代码示例:
//迭代器删除
@Test
public void del02() {
Iterator<Integer> it=list.iterator();
while (it.hasNext()) {
Integer value=it.next();
if(value==3) {
it.remove();
}
}
System.out.println(list);
}
运行结果:
所有为3的元素已全部删除
建议使用迭代器删除
1.3LinkedList
- LinkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部
- 线程不安全
- LinkedList可被用作堆栈(stack)【包括了push,pop方法】,队列(queue)或双向队列(deque)
- 以双向链表实现,链表无容量限制,允许元素为null,线程不安全
- 适合做随机的增加或删除
效率太慢 不常用
1.4 Vector
- 相比于LinkedList 线程是安全的
- 但是由于效率慢 也不是很常用
1.5CopyOnWriteArrayList
- 写时复制
- 线程安全
- 适合于读多,写少的场景
- 写时复制出一个新的数组,完成插入、修改或者移除操作后将新数组赋值给array
- 比Vector性能高
- 最终一致性
- 实现了List接口,使用方式与ArrayList类似
二.set集合
- 特点:无序,不重复
- 遍历:foreach,迭代器
- 扩容: 初始容量16,负载因子0.75,扩容增量1倍
2.1Hashset
- 它存储唯一元素并允许空值
- 依据对象的hashcode来确定该元素是否存在
- 由HashMap支持
- 不保持插入顺序
- 非线程安全
- 性能参数:初始容量,负载因子
- 默认值: 初始容量16,负载因子0.75
private HashSet<Integer> set = new HashSet<>();
@Before
public void set01() {
set.add(1);
set.add(2);
set.add(2);
set.add(3);
set.add(4);
set.add(5);
}
@Test
public void test() {
for (Integer integer : set) {
System.out.println(integer);
}
}
运行结果
实现了自动去重 所以需要去重的集合 可以借助hashset
2.2TreeSet
- TreeSet
- 是一个包含有序的且没有重复元素的集合
- 作用是提供有序的Set集合,自然排序或者根据提供的Comparator进行排序
- TreeSet是基于TreeMap实现的
三. map集合
- 特点:
- 无序,键值对,键不能重复,值可以重复,
- 键重复则覆盖,没有继承Collection接口
- 扩容:初始容量16,负载因子0.75,扩容增量1倍
- 遍历:
- 先获取所有键的Set集合,再遍历(通过键获取值)
- 取出保存所有Entry的Set,再遍历此Set即可
3.1Hashmap
线程不安全,最常用,速度快
内部采用数组来存放数据(红黑树)
3.2HashTable
线程安全,不太常用
3.3ConcurrentHashMap
线程安全,比HashTable性能高
3.4TreeMap
- key值按一定的顺序排序
- 添加或获取元素时性能较HashMap慢
- 因为需求维护内部的红黑树,用于保证key值的顺序
3.5LinkedHashMap
LinkedHashMap是有序的,且默认为插入顺序
当我们希望有顺序地去存储key-value时,就需要使用LinkedHashMap了
遍历方式
Map<String, String> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("name1", "josan1");
linkedHashMap.put("name2", "josan2");
linkedHashMap.put("name3", "josan3");
Set<Entry<String, String>> set = linkedHashMap.entrySet();
Iterator<Entry<String, String>> iterator = set.iterator();
while(iterator.hasNext()) {
Entry entry = iterator.next();
String key = (String) entry.getKey();
String value = (String) entry.getValue();
System.out.println("key:" + key + ",value:" + value);
}
四 、排序
java.lang.Comparable
java.util.Comparator
4.1 工具类
Collections 提供一组静态方法操作集合
Arrays 提供一组静态方法操作数组