Set与Map集合

Set集合

  • Set集合中,没有下标的概念。
  • Set集合,是⼀个去重复的集合。 在Set集合中不会添加重复的元素的!

在向⼀个Set集合中添加元素的时候, 会先判断这个元素是否已经存在了。如果存在, 则不再添加。

  • Set集合中, 数据的存储是⽆序的。

⽆序: 所谓的⽆序, 其实指的是元素的添加顺序和存储顺序是不⼀致的。
⽆序, 并不意味着随机!

Set接⼝, 是继承⾃Collection接⼝的。 Set接⼝中的⽅法, 都是从Collection接⼝中
继承下来的, 并没有添加新的⽅法

Map集合

Map是双列集合的顶级接⼝, 这个接⼝并没有继承⾃Collection接⼝。在Map中, 更多强调的是⼀层映射关系。 在Map中存储的数据, 是⼀个个的键值对(Key-Value-Pair), 键和值是⼀⼀对应的。

需要注意:

由于Map集合并没有实现Iterable接⼝, 因此这个集合是不能使⽤增强for循环遍历的。

Set集合

HashSet与TreeSet的区别

  • HashSet:底层是哈希表,线程不安全的
  • TreeSet:底层是⼆叉树,线程不安全的

Set集合的两个实现类HashSet与LinkedHashSet,底层实现都是哈希表。

  • Hash,⼀般翻译做“散列”,也有直接⾳译为“哈希”的,它是基于快速存取的⻆度设计的,也是⼀种典型的“空间换时间”的做法。顾名思义,该数据结构可以理解为⼀个线性表,但是其中的元素不是紧密排列的,⽽是可能存在空隙。
  • 散列表(Hash table,也叫哈希表),是根据键值码值(Key value)⽽直接进⾏访问的数据结构。也就是说,它通过把键值码值映射到表中⼀个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数。
  • Hash表的组成是”数组+链表”这些元素是按照什么样的规则存储到数组中呢。⼀般情况是通过hash(key)%len获得,也就是元素的key的哈希值对数组⻓度取模得到。

⽐如下图哈希表中,12%16=12,28%16=12,108%16=12,140%16=12。所以
12、28、108以及140都存储在数组下标为12的位置

在这里插入图片描述

  • HashSet & LinkedHashSet

在这里插入图片描述

解释:是通过调⽤元素的hashCode和equals⽅法实现去重,⾸先调⽤hashCode⽅法,拿到当前对象的哈希码值,去让两个对象的哈希码值进⾏⽐较,如果不同,直接认为是两个对象,不再去调⽤equals,如相同,再继续调⽤equals⽅法,返回true认为是⼀个对象,返回false认为是两个对象

TreeSet

TreeSet是⼀个Set接⼝的实现类,底层实现是⼆叉树。这样的集合,会对添加进集合的元素进⾏去重的处理。 同时, 这个集合会对添加进⼊的元素进⾏⾃动的升序排序。

Comparable接⼝

如果某⼀个类实现这个接⼝, 表示⾃⼰实现了⼀个可以和⾃⼰的对象进⾏⼤⼩⽐较的规则。 此时, 这个类的对象就可以直接存储进TreeSet集合中了。 因为此时TreeSet集合已经知道了怎么对两个这个类的对象进⾏⼤⼩⽐较。

Comparator接⼝(⼈⼯排序)

定义:使⽤实现了Comparator接⼝的compare()⽅法的⽐较器对象进⾏⽐较

分析1:有了Comparable,为什么还要有comparator?

  • 对于⾃定义的类,代码是我们⾃⼰编写的,所有在排序时不管是通过Comparator还是Comparable,排序规则我们都可以⾃⼰制定,所以最终使⽤那种⽅法没有太⼤的区别
  • 对于系统类,影响⾮常⼤.系统类中的代码我们只能⽤,不能改.这也就意味着系统类内部通过Comparable实现的⽐较规则已经确定了.这时我们想使⽤其他的规则对当前的系统类对象进⾏⽐较,只能使⽤Comparator⾃⼰重新制定⽐较规则.

**分析2:**⼈⼯排序和默认排序那个优先级⾼?

⼈⼯排序的优先级⾼于默认排序.

我们可以让TreeSet同时获取到Comparator和Comparable的⽐较⽅法,此时对于系统类来说默认排序是系统⾃带的,通过Comparator实现的⼈⼯排序规则是我们想要的,所以系统必须让⼈⼯排序优先于默认排序,才能正常的使⽤后加的排序规则.

Comparable与Comparator的使⽤场景

  • 如果这个对象, 在项⽬中⼤多数的情况下, 都采⽤相同的⼤⼩⽐较的⽅式。 ⽐如: ⼀个Person类, 在⼤多数情况下, 都是按照年龄进⾏⼤⼩⽐较的。 此时就可以让Person类实现Comparable接⼝。
  • 如果某⼀个类的对象, 在临时进⾏⼤⼩⽐较的时候, 使⽤的与默认的⽐较不⼀样的规则。 ⽐如: ⼀个Person类, ⼤多数情况下, 都是使⽤的年龄进⾏⼤⼩⽐较的, 但是临时需要使⽤身⾼进⾏⼀次⽐较, 此时就可以使⽤ Comparator临时完成了。 ⽽且, Comparator的优先级要⾼于Comparable。
  • 系统类想实现新的⽐较规则,使⽤Comparator

TreeSet的去重

⽆论使⽤Comparator还是Comparable,如果两个对象进⾏⼤⼩⽐较的结果是0,此时代表这两个对象是相同的对象。 在TreeSet中会完成排重的处理。

注意: TreeSet中元素的去重只与对象的⼤⼩⽐较结果有关。 与hashCode()、equals(), 没有任何关系。

Map集合

返回值⽅法描述
Vput(K key, V value)将⼀个键值对插⼊到集合中。 在Map集合中,不允许出现重复的键。如果添加的键重复了,会⽤新的值覆盖掉原来的值。并返回被覆盖的原来的值。
VputIfAbsent(K key, Vvalue)将⼀个键值对插⼊到集合中。 向集合中添加元素的时候,如果这个键已经存在了,则不进⾏添加。 返回集合中已经存在的这个键对应的值。
voidputAll(Map<K, V>map)将⼀个Map集合中所有的键值对添加到当前集合中。
booleanremove(Object key,Object value)通过键值对进⾏删除。 只有当键和值⼀⼀匹配的时候, 才会进⾏删除。
voidclear()清空集合。
Vreplace(K key, V value)修改指定的键对应的值, 并返回被覆盖的值。
booleanreplace(K key, V oldValue, V newValue)只有当key和oldValue是匹配的情况下,才会将值修改成newValue。
voidreplaceAll(BiFunction<K,V, V> biFunction)对集合中的元素进⾏批量的替换 将集合中的每⼀个键值对,带⼊到BiFunction的⽅法中, 使⽤接⼝⽅法的返回值替换集合中原来的值。
Vget(K key)通过键, 获取值。 如果键不存在,返回null。
VgetOrDefault(K key)通过键, 获取值。 如果键不存在,返回默认的值。
intsize()获取集合中的元素数量(有多少个键值对)
booleanisEmpty()判断集合是否为空
booleancontainsKey(K key)判断是否包含指定的键
booleancontainsValue(V value)判断是否包含指定的值
SetkeySet()获取由所有的键组成的集合(因为键是不允许重复的, 因此这⾥返回的是Set集合)
Collectionvalues()获取由所有的值组成的集合

Map集合的遍历

使⽤keySet进⾏遍历

  1. 可以使⽤keySet()⽅法获取到集合中所有的键。
  2. 遍历存储了所有的键的集合,依次通过键获取值。
// 1. 获取存储了所有的键的集合
Set<String> keys = map.keySet();
// 2. 遍历这个Set集合
for (String key : keys) {
    // 2.1. 通过键获取值
    String value = map.get(key);
    // 2.2. 展示⼀下键和值
    System.out.println("key = " + key + ", value = " +value);
}

使⽤forEach⽅法

这个forEach⽅法, 并不是Iterable接⼝中的⽅法。 是Map接⼝中定义的⼀个⽅法。
从功能上将, 与Iterable中的⽅法差不多。 只是在参数部分有区别。

default void forEach(BiConsumer<? super K, ? super V> action)

map.forEach((k, v) -> {
    // k: 遍历到的每⼀个键
    // v: 遍历到的每⼀个值
    System.out.println("key = " + k + ", value = " + v);
});

使⽤EntrySet进⾏遍历

Entry<K, V>:

是Map中的内部静态接⼝, ⼀个Entry对象我们称为⼀个实体,⽤来描述集合中的每⼀个键值对。

// 1. 获取⼀个存储有所有的Entry的⼀个Set集合
Set<Map.Entry<String, String>> entries = map.entrySet();
// 2. 遍历Set集合
for (Map.Entry<String, String> entry : entries) {
    // 2.1. 获取键
    String key = entry.getKey();
    // 2.2. 获取值
    String value = entry.getValue();
    // 2.3. 展示
    System.out.println("key = " + key + ", value = " + value);
}
//通过setValue可以去修改原始map的值
//映射项(键-值对)。Map.entrySet ⽅法返回映射的 collection视图,其中的元素属于此类。
//获得映射项引⽤的唯⼀ ⽅法是通过此 collection 视图的迭代器来实现。这些 Map.Entry 对象仅
//在迭代期间有效;更正式地说,如果在迭代器返回项之后修改了底层映射,则
//某些映射项的⾏为是不确定的,除了通过 setValue 在映射项上执⾏操作之外。
//entry.setValue("hello");

HashMap

HashMap基本实现

注意:HashMap可以实现排序:因为他的底层数据结构是由数组+链表+⼆叉树共同实现的.所以可以排序.同时这样做的⽬的是提⾼数据存储的效率.

HashMap与Hashtable的区别

  1. HashMap是线程不安全的集合, Hashtable是线程安全的集合。
  2. HashMap允许出现null键值, Hashtable是不允许的。
  3. HashMap的⽗类是AbstractMap, Hashtable的⽗类是Dictionary。
  4. HashMap的Map接⼝的新的实现类, 底层算法效率优于Hashtable。

TreeMap

原理

与TreeSet⼀样,进⾏排列,只是TreeMap是按照键的⼤⼩实现,对于值是不管的.我们可以将TreeSet中的值理解成TreeMap中的键.

注意点

  1. 什么类型的数据类型可以作为key?
    实现了Comparable接⼝的compareTo()⽅法
    实现了Comparator接⼝的compare()⽅法

  2. 经常作为key的有:
    String,包装类,⾃定义的实现了要求的类

  3. 不可以的代表:数组,ArrayList,LinkedList(如果给他们建⽴的⽐较器也可以⽐较,但是不建议使⽤)

  4. 元素可不可以作为key,跟元素内部的成员有没有关系

    元素可以作为key,跟元素内部的成员没有关系。

LinkedHashMap

  • 与HashMap类似的,底层多维护了⼀个链表, 记录每⼀个键的存储顺序。也就是说, 在LinkedHashMap中, 键值对的添加顺序可以得到保障。 类似于LinkedHashSet与HashSet。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值