无序不可重复:
存储是顺序和取出的顺序不同,
不可重复
放到HashSet集合中的元素实际上是放到了HashMap集合的key部分了
无序不可重复的但是存储的元素可以自动按照大小顺序来排序
称为:可排序集合。
无序:指的是存进去的顺序和取出来的顺序不同 并且没有下标
<> 泛型 集合中元素更加统一,让我们写代码的时候很少再进行向下转型
增强for循环 foreach 不带下标
Map 和Collection没有继承关系
Map集合以key和value的方式存储数据:键值对
key和value都是引用数据类型
key和value都是存储对象的内存地址。
key起主导地位,value是key的一个附属品
Map中常用的方法:
void | **[clear](../../java/util/Map.html#clear())**() 从此映射中移除所有映射关系(可选操作)。 | 清空Map集合 |
---|---|---|
boolean |
**[containsKey](../../java/util/Map.html#containsKey(java.lang.Object))**(Object key) 如果此映射包含指定键的映射关系,则返回 true 。 |
判断Map中是否包含某些个key |
boolean |
**[containsValue](../../java/util/Map.html#containsValue(java.lang.Object))**(Object value) 如果此映射将一个或多个键映射到指定值,则返回 true 。 |
是否包含某些个value |
Set<Map.Entry<K,V>> |
**[entrySet](../../java/util/Map.html#entrySet())**() 返回此映射中包含的映射关系的 |
将Map集合转换成Set集合 |
boolean |
**[equals](../../java/util/Map.html#equals(java.lang.Object))**(Object o) 比较指定的对象与此映射是否相等。 |
|
V |
**[get](../../java/util/Map.html#get(java.lang.Object))**(Object key) 返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null 。 |
通过key获取value |
int |
**[hashCode](../../java/util/Map.html#hashCode())**() 返回此映射的哈希码值。 |
|
boolean |
**[isEmpty](../../java/util/Map.html#isEmpty())**() 如果此映射未包含键-值映射关系,则返回 true 。 |
Map集合中元素个数是否为0 |
Set<K> |
**[keySet](../../java/util/Map.html#keySet())**() 返回此映射中包含的键的 |
获取所有的key |
V |
**[put](../../java/util/Map.html#put(K, V))**(K key, V value) 将指定的值与此映射中的指定键关联(可选操作)。 |
向Map集合中添加键值对 |
Set< >
【注意】:Map集合通过entrySet()方法转换成的这个Set集合,Set集合中元素的类型是Map.Entry<k,v>
【Map.entry 和String 一样,都是一种类型的名字,只不过:Map.entry 是一种静态内部类,是Map中的静态内部类】
?
package com.zhang.san;
?
import java.util.Collection;
import java.util.HashMap;
?
public class Map {
public static void main(String[] args) {
java.util.Map<Integer,String> map = new HashMap<>();
map.put(1,"wowowo");
map.put(2,"zhang");
map.put(3,"zhangjunlong ");
map.put(2,"woshizhang junlo");
System.out.println(map.get(2));
map.remove(2);
System.out.println(map.size());
System.out.println(map.get(2));//null
map.clear();
System.out.println(map.size());
System.out.println(map.containsValue("zhangjunlong"));
map.put(1,"zhangjunlong");
System.out.println(map.containsValue("zhangjunlong"));
map.put(3,"woshizhangjunlonh");
map.put(4,"zhanfjunlonmg");
Collection suoyoude =map.values();
for (String s : map.values())
{
System.out.println(s);
?
}
}
}
?
遍历Map集合
获取所有的key,所有的key是一个Set集合
Set<Integer>keys = map.keySet();
遍历key。通过key获取value
迭代器遍历所有的value
Set<Integer> keys = map.keySet();
Iterator<Integer> it = keys.iterator();
?
while ( it.hasNext()){
Integer key = it.next();
String value = map.get(key);
System.out.println(
key + "="+ value
);
?
}
foreach 也可以
for (Integer key : keys){
System.out.println(key + "=" + map.get(key));
}
?
以上的方法是把Map集合直接全部转换成Set集合
Set集合中元素的类型是:Map.Entry
foreach
for (java.util.Map.Entry<Integer, String> node:set)
{
System.out.println(node.getKey() + "--->"+node.getValue());
}
?
}
这种方式效率比较高,因为获取key和value都是直接从node对象对获取的属性值。
这种方式比较适合于大数据量
哈希表或者散列表的数据结构
门帘子
HashMap集合底层是哈希表|散列表的数据结构
哈希表是一个怎么样的数据结构
哈希表是一个数组和单向链表的结合体
数组:在查询方面效率很高,随机增删方面效率较低
单向链表:在随机增删方面效率较高,在查询方面效率较低
哈希表将以上两种数据结构融合在一起,充分发挥了他们各自的优点
HashMap集合底层的源代码
哈希值(哈希值是key的HashCode()方法的执行结果。hash值通过哈希函数|算法,可以转换存储成数组的下标)
HashMap底层实际上就是一个数组
Node<K,V>[] table ;
哈希表、散列表:一维数组,这个赎罪中每一个元素是一个单向链表(数组和链表的结合体)
final int hash 哈希值:哈希值(哈希值是key的HashCode()方法的执行结果。hash值通过哈希函数|算法,可以转换存储成数组的下标)
final K key 存储到Map集合中的那个key
V value 存储到Map集合中的那个value
Node<K,V>next; 下一个节点的内存地址
map.put(k,v)
v=map.get(k)
以上两种方法的实现原理,是必须掌握的
第一步:先将k,v封装到Node对象当中
第二步:底层先调用k的hashCode()方法得到hash值。然后通过哈希函数,哈希算法,将hash值转换成数组的下标,下标的位置如果没有任何元素,就把Node添加到这个位置上了,如果下标对应的位置上有链表,此时会拿着k和链表上每一个节点中的k进行equals,如果所有的equals方法返回值都是false,那么这个新节点将会被添加到链表的末尾,如果其中有一个equals返回了true,那么这个节点的value将会被覆盖
第一步:先调用k的hashCode()方法得到哈希值,通过哈希算法转成数组下标,通过数组下标快速定位到某个位置上,如果这个位置上什么也没有,返回null,如果这个位置上有单向链表,那么会拿着参数k和单向链表上的每一节点中的k进行equals,如果所有equals方法返回值是false,那么get方法返回null,只要其中有一个节点的k和参数k,equals的时候返回true,那么此时这个节点的value就是我们要找的value,get方法最终返回这个要找的value
增删是在链表上完成,查询也不需要扫描全部,只需要部分扫描
重点: 通过讲解可以得出HashMap集合的key,会先后调用两个方法,一个方法是hashCode()一个方法是equals(),那么这两个方法都需要重写
因为equals方法默认比较的是两个对象的内存地址,我们应该比较的是内容
无序,不可重复
为什么无序,因为不一定挂到哪个单向链表上
不可重复是怎么保证的
equals方法来保证HashMap集合的key不可重复、
如果key重复了,value会覆盖
放在HashMap集合key部分的元素其实就是放到HashSet集合中了
所以HashSet集合中的元素也需要同时重写hashCode()+equals()方法
注意:同一个单向链表的所有节点的Hash相同,因为他们的数组下标是一样的,但是同一个链表上k和k的equals方法肯定返回的都是false,都不相等
hashCode()方法重写的时候
假设将所有的hashCode()方法返回值固定为某个值,那么会导致底层哈希表变成纯单向链表,这种情况我们称为:散列分布不均匀
什么是散列分布均匀?
这个默认架子啊因子是当HashMap集合底层数组的容量达到75%的时候,数组开始扩容
重点:记住。HashMap集合初始化容量必须是2的倍数,这也是官方推荐的,
这是因为达到散列均匀,为了提高HashMap集合的存取效率,所必须的。
向map集合中存,以及从Map集合中取,都是先调用key的hashCode方法,然后再调用equals方法!
equals方法有可能调用,也有可能不调用
拿put(k,v)举例,什么时候equals不会调用?
k.hashCode()方法返回哈希值
哈希值经过哈希算法转换成数组下标
数组下标位置上如果是null,equals不需要执行
原文:https://www.cnblogs.com/geren/p/14827258.html