一、Set
Set:不包含重复元素的集合,不保证顺序。而且方法和Collection一致。
Set集合有HashSet、TreeSet、LinkedSet这三个集合。
1.HashSet
哈希表结构,不同步,保证元素唯一性的方式依赖于:hashCode(),equals()方法。
什么是哈希表?
散列表(Hash table,也叫哈希表),是根据键(Key)而直接访问在内存存储位置的数据结构。也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数(哈希函数),存放记录的数组称做散列表。
Set实现的子类
HashSet
此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺 序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。 是一个存放链表的数组。
操作包括:add、remove、contains、size
代码示例:
@Test
void testSet01() {
// HashSet 是java中的一个标准的哈希表
Collection<Integer> nums = new HashSet<>();
nums.add(123);
nums.add(456);
nums.add(789);
nums.add(1);
nums.add(13);
nums.add(258);
nums.add(10);
// add方法会返回一个boolean,表示是否添加成功
System.out.println(nums.add(31));
// 添加失败,返回false,表示之前已经存在了这个值
System.out.println(nums.add(31));
System.out.println(nums.contains(1));
System.out.println(nums.contains(11));
System.out.println(nums);
}
TreeSet
可以对Set集合中的元素进行排序。使用的是二叉树结构。如何保证元素唯一性的呢?使用 的对象比较方法的结果是否为0,是0,视为相同元素不存。元素自身具备自然排序,其实就是实现了 Comparable接口重写了compareTo方法。
- E ceiling(E e) : 返回此 set 中大于等于给定元素的最小元素;如果不存在这样的元素,则返回 null
- E floor(E e) :返回此 set 中小于等于给定元素的最大元素;如果不存在这样的元素,则返回 null
- E first() :返回此 set 中当前第一个(最低)元素
- E last() :返回此 set 中当前最后一个(最高)元素
- E higher(E e) :返回此 set 中严格大于给定元素的最小元素;如果不存在这样的元素,则返回 null
- E lower(E e) :返回此 set 中严格小于给定元素的最大元素;如果不存在这样的元素,则返回 null
代码示例:
@Test
void testSet03() {
Set<String> ss = new TreeSet<>();
// 有序的集合
ss.add("apply");
ss.add("huawei");
ss.add("mi");
ss.add("mm");
ss.add("vivo");
ss.add("OPPO");
System.out.println(ss);
}
@Test
void testSet04() {
Set<Integer> ss = new TreeSet<>();
// 有序的集合
ss.add(1);
ss.add(2);
ss.add(33);
ss.add(333);
ss.add(12);
ss.add(102);
ss.add(50);
System.out.println(ss);
}
二、Map集合
映射:将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
Map集合就是用来存放具有对应关系的数据的。即就是key对 应value这样的关系,并且要求key不能重复。
Map接口常用功能
- void clear() :从此映射中移除所有映射关系(可选操作)。
- boolean containsKey(Object key) :如果此映射包含指定键的映射关系,则返回 true 。
- boolean containsValue(Object value) :如果此映射将一个或多个键映射到指定值,则返回 true 。 Set> entrySet() :返回此映射中包含的映射关系的 Set 视图。
- boolean equals(Object o) :比较指定的对象与此映射是否相等。
- V get(Object key) :返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null 。 int hashCode() :返回此映射的哈希码值。
- boolean isEmpty() :如果此映射未包含键-值映射关系,则返回 true 。
- Set keySet() :返回此映射中包含的键的 Set 视图。
- V put(K key, V value) :将指定的值与此映射中的指定键关联(可选操作)。
- void putAll(Map m) : 从指定映射中将所有映射关系复制到此映射中 (可选操作)。
- V remove(Object key) :如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。
- int size() :返回此映射中的键-值映射关系数。
- Collection values() :返回此映射中包含的值的 Collection 视图。
HashMap代码示例:
@Test
void testMap01() {
Map<String, Integer> mps = new HashMap<>();
mps.put("name", 123);
mps.put("age", 23);
mps.put("gender", 56);
// 当key重复时,不会创建多个键值对,只会进行覆盖
mps.put("gender", 100);
System.out.println(mps);
System.err.println(mps.size());
System.err.println(mps.get("name"));
// 如果获取的key不存在,则返回空
System.err.println(mps.get("nickname"));
// 在HashMap中,以null作为key,可以不?
// 在HashMap中,可以使用null作为key
mps.put(null, 123);
System.out.println(mps);
System.out.println(mps.get(null));
}
hashMap原码解析:
key是唯一的,不能重复,通过key可以找到值,但不能通过值找到对应的key
在Java中,key可以是任意类型
当key重复时,长度大小不变
但是当key重复且值改变,那么最后出现的值会覆盖前面的值
如果获取的key不存在,则返回null
在hashMap中,可以将null作为key,但是只能用一次
@Test
void testMap02() {
Map<String, String> mps = new HashMap<>();
mps.put("name", "啦啦啦");
mps.put("age", "20");
mps.put("gender", "男");
// 获取时,如果存在,则返回,如果不存在,则给定一个默认值
System.out.println(mps.getOrDefault("name2", "佚名"));
System.out.println(mps.containsKey("name"));
System.out.println(mps.containsKey("nickname"));
// 根据key 移除整个键值对
// System.out.println(mps.remove("name"));
// System.out.println(mps);
// 根据key和value,移除整个键值对
// System.out.println(mps.remove("age", "20"));
System.out.println(mps);
// 注意,仅仅是替换key对应的值,如果没有,不会添加
mps.replace("name", "啦啦啦");
System.out.println(mps);
}
getOrDefault("K","V")
remove("key")会移除整个键值对
remove("K","V")不能移除不存在的键值对,只有两个都相同才能移除,更加严谨
replace("K","V")
通过key将值替换,不能替换不存在的key的值
遍历map结构迭代只能不断往前或往后
entrySet()一个个迭代键值对
jdk8提供新的map自身迭代方式
正则表达式:双斜杠表示一个斜杠,为了和单斜杠区别
哈希冲突:
什么是哈希冲突?
是由于哈希算法被计算的数据是无限的,而计算后的结果范围有限,所以总会存在不同的数据经过计算后得到的值相同,这就是哈希冲突。
哈希冲突的四种解决方案
1.再哈希法
2.开放定址法
3.拉链法、列表法
4.公共的缓冲区
jdk7之前是头插法,8之后是尾插法
当数组容量到3/4时会触发扩容,不是节点
1<<4=16 即2^4
整数的最大值2^31-1