java基础-第十一章 集合

java基础

待补



前言

本篇聊一下java基础中的一大重要内容——集合。


1.集合类概述

1.1常用集合知识体系

![[./_resources/12.第十二章_集合类.resources/unknown_filename.12.png]]

以上为常用集合类继承体系,作为扩充,我们可能还需要额外了解一下HashTableConcurrentHashMap

1.2和数组的区别

集合和数组一样是一种容器,但也有区别:

  • 数组长度固定,集合长度可变。
  • 数组存放基本类型或引用类型,集合存放引用类型。

2.Collection单列集合根接口

是单列集合,是list接口和set接口的父接口,单例集合的根接口。
Collection常用方法(set和list接口共用):
add(E e):把元素填入集合
remove(Object o):把元素从集合中移除
isEmpty():判空,返回boolean值
iterator():迭代器,放回集合中每个对象,用于遍历
size():集合中元素个数,返回int值
下面演示用迭代器遍历集合元素:

import java.util.*  
public class Muster{  
    public static void main(String args[]){  
    //创建集合对象  
        Collection list=new ArrayList<>();  
        //填入三条数据  
        list.add("测试数据1");  
        list.add("测试数据1");  
        list.add("测试数据1");  
        //调用iterator()方法获取迭代器对象  
        Iterator it =list.iterator();  
        //使用hasNext()方法判断集合是否结束  
        while(it.hasNext()){  
        //把下一个元素赋值给变量str  
            String str =(String)it.next();  
            //打印当前元素  
            sout(str);  
        }  
    }  
}

3.List集合

3.1介绍

Collection的一个子接口

  • 集合中元素允许重复,元素顺序就是对象插入顺序
  • 可以使用索引来访问。
  • 除了Collection接口的方法外还额外定义了两个方法:

get(int index):获取指定索引位置的元素
set(int index,object o):修改指定位置的元素为指定对象

3.2ArrayList

实现了可变的数组,可以保存所有种类元素,包括null。
根据索引访问元素,查询快插入慢,如下是常用方法。

常用方法

添加元素
boolean add(E e):将指定的元素添加到此列表的末尾(可选操作)。
void add(int index, E element):将指定的元素插入此列表中的指定位置(可选操作)。
boolean addAll(Collection<? extends E> c):将指定集合中的所有元素添加到此列表的末尾,顺序由指定集合的迭代器确定(可选操作)。
boolean addAll(int index, Collection<? extends E> c):将指定集合中的所有元素都插入到列表中的指定位置(可选操作)。

删除元素
E remove(int index):移除此列表中指定位置上的元素(可选操作)。
boolean remove(Object o):从列表中移除指定元素的第一个匹配项(如果存在)(可选操作)。
boolean removeAll(Collection<?> c)**:移除列表中那些也包含在指定集合中的所有元素(可选操作)。 **boolean retainAll(Collection<?> c):仅保留此列表中那些也包含在指定集合中的元素(可选操作)。
void clear():移除此列表中的所有元素(可选操作)。

访问元素
E get(int index):返回列表中指定位置的元素。
int indexOf(Object o):返回此列表中首次出现的指定元素的索引,或如果此列表不包含元素,则返回 -1。
int lastIndexOf(Object o):返回此列表中最后出现的指定元素的索引,或如果此列表不包含索引,则返回 -1。

3.4LinkedList

使用链表保存元素,查询慢插入快。
底层使用双链表存储数据,LinkedList 只有 3 个属性,分别为: 头节点 first 、 尾节点 last 以及代表数量的 size。
![[./_resources/12.第十二章_集合类.resources/unknown_filename.png]]

其中Node是内部类,内部记录数据、前一节点、后一节点
![[./_resources/12.第十二章_集合类.resources/unknown_filename.1.png]]

4Set集合

  • 没有特定排序规则,
  • 元素不可重复

实现类有:
HashSet:
由hash表支持,不保证迭代顺序
TreeSet:
可以保证遍历时候的顺序(使用迭代器取出的元素会按某种规则排布)

4.1Hashset

底层是哈希表哈希表底层是一个数组,通过哈希值计算出存储的索引位置。
哈希值通过Object对象中的hashcode方法来计算。
哈希表:jdk1.8前是数组+链表,jdk1.8后是数组+链表+红黑树

hashcode方法:默认使用地址值计算,因此各个对象的哈希值不同。但可以重写hashcode方法,让其用属性值进行计算,这样一来即使是不同对象,只要属性值相同,也会拥有相同的哈希值。
![[./_resources/12.第十二章_集合类.resources/unknown_filename.2.png]]

hashSet元素添加底层原理
![[./_resources/12.第十二章_集合类.resources/unknown_filename.3.png]]

转换红黑树的时机
![[./_resources/12.第十二章_集合类.resources/unknown_filename.4.png]]

明白hashSet中存储的原理后,需要注意:
![[./_resources/12.第十二章_集合类.resources/unknown_filename.5.png]]

三大特点解析
为什么无序?
哈希表底层是一个数组,遍历哈希表就是从头遍历这个底层数组,但存放的数据在这个数组中并不是按顺序存放,所以遍历底层数组时也不会是存入时的顺序。
(比如我第一个存入的数据计算了哈希值后存储在数组的2号位,但第二个存入的数据计算哈希值后却存储在数组的1号位,于是获取的顺序就会反过来)
![[./_resources/12.第十二章_集合类.resources/unknown_filename.6.png]]

为什么无索引?
因为底层的链表和红黑树本身就不是连续存储的,无法通过索引快速获取元素,使用hash的方式已经能够快速获取数据了。所以也就没必要引入索引这个概念了。
为什么数据不重复?
上面提到底层存储时会使用hashcode判断存储位置,然后使用equals()方法比较元素,元素内容相同就不进行存储。

补充:其实本身HashSet底层就是用一个HashMap存数据,只是将value对使用者隐藏了而已。

4.2LinkedHashSet

相较HashSet,额外用双链表来链接所有元素。
于是相较HashSet,可以保证存取顺序一致

4.3TreeSet

底层使用红黑树实现,可以对元素进行排序。
![[./_resources/12.第十二章_集合类.resources/unknown_filename.7.png]]

如果是存储自定义的类对象,还需要在自定义类中提供比较规则。
有两种方式来决定TreeSet的比较规则:重写compareTo、比较器
4.3.1自定义比较规则

需要自定义类实现Comparable接口并重写其中的compareTo方法,在该方法中设置比较规则。
如:我们用学生类的年龄为标准进行排序:
![[./_resources/12.第十二章_集合类.resources/unknown_filename.8.png]]

这个方法是TreeSet在进行元素添加时使用的参考函数,用来确定新元素应该添加到树的哪一个位置。
![[./_resources/12.第十二章_集合类.resources/unknown_filename.9.png]]

新元素会从根开始与已有元素依次比较,返回值为负数就把新元素放左子树上,返回值为正数就把新元素放右子树上。如果要添加的位置已有元素,就继续比较。最终形成查找树,再通过红黑树规则转换为真正的红黑树。

4.3.2比较器指定规则

这种方式可以在创建集合对象时传入一个比较器对象来指定规则。
规则的具体用法与上一种方式一样。
![[./_resources/12.第十二章_集合类.resources/unknown_filename.10.png]]


5Map集合

![[./_resources/12.第十二章_集合类.resources/unknown_filename.11.png]]

存储key-value映射,一个key只指定一个value,但一个value可以被多个key指定

5.1Map接口

Map接口额外提供的方法:
put(K key,V value):集合中添加映射
containsKey(Object key):查看有没有指定名称的key的元素
containsValue(Object value):查看有没有指定名称的value元素
get(Object key):获取传入的key对应的value值
keySet():返回一个由所有的key组成的Set集合
values():返回集合中所有value组成的Collection集合

5.2HashMap

底层也是哈希表,因此存储的规则等与前面说的hashSet一致,只不过存储的元素是Entry<K,V>对象。
使用hashcode和equals方法保证元素不重复
不保证元素顺序,可以使用null键和null值
添加元素时的判断逻辑如下:
![[./_resources/12.第十二章_集合类.resources/unknown_filename.13.png]]

也就是说,HashMap并不在意一个Node中的Value是什么,仅仅使用key(使用hashcode和equals方法)来判断整个Node结点是否能够添加进去。

5.3LinkedHashMap

继承自HashMap,额外有双链表链接存储的Entry<K,V>元素。

5.4TreeMap

可以保证元素按顺序输出,但键和值不可以为空值
与TreeSet一样底层是红黑树

补充:即HashMap与HashSet一样,TreeMap与TreeSet一样。区别无非是list系列的集合存储普通的引用数据,Map系列集合存储Entry<K,V>类型对象。

5.5HashTable

底层方法被sychonized修饰,可保证并发安全。

5.6ConcurrentHashMap

使用分段锁保证并发安全


总结

本篇中简要介绍一下java中的集合。

  • 25
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值