文章目录
一、Map接口
1、Map和Collection没有继承关系。
2、Map集合以key
和value
的方式存储数据:键值对
key
和value
都是引用数据类型。
key
和value
都是存储对象的内存地址。
key
起主导的地位,value
是key
的一个附属品。
1、Map接口中的常用方法
V put(K key, V value)
向Map集合中添加键值对
V get(Object key)
通过可以获取value
void clear()
清空Map集合
boolean containKey(Object key)
判断Map中是否包含某个key
boolean containValue(Object value)
判断Map中是否包含某个value
boolean isEmpty()
判断Map集合中元素个数是否为0
Set<K> keySet()
获取Map集合所有的key(所有的键是一个set集合)
V remove(Object key)
通过key删除键值对
int size()
获取Map集合中键值对的个数。
Collection<V> values()
获取Map集合中所有的value,返回一个Collection
Set<Map.Entry<K,V>> entrySet() b
将Map集合转换成Set集合
注意:
Map.Entry和String一样,都是一种类型的名字,只不过:Map.Entry是静态内部类,是Map中的静态类
Map集合通过entrySet()的方法转换成的这个Set集合,Set集合中的元素的类型都是Map.Entry<K,V>
2、遍历Map集合
import java.util.*;
public class MapText {
public static void main(String[] args) {
//第一种方式:获取所有Key,通过遍历key。来遍历value
Map<Integer,String> map = new HashMap<>();
map.put(1,"zhangsan");
map.put(2,"lisi");
map.put(3,"wangwu");
map.put(4,"zhaoliu");
1、第一种方式:获取所有Key,通过遍历key。来遍历value
//遍历Map集合
//获取所有的key,所有的key是一个Set集合
Set<Integer> keys = map.keySet();
//遍历key,通过key返回value
//迭代器也可以
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));
}
2、第二种方法:Set<Map.Entry<K,V>> entrySet() b
将Map集合转换成Set集合,Set集合中元素的类型是:Map.Entry
Map.Entry和String一样,都是一种类型的名字,只不过:Map.Entry是静态内部类,是Map中的静态类
Set<Map.Entry<Integer,String>> set = map.entrySet();
//遍历Set集合,每一次取出一个Node
//迭代器
Iterator<Map.Entry<Integer,String>> it = set.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
或者
Set<Map.Entry<Integer,String>> set = map.entrySet();
//遍历Set集合,每一次取出一个Node
//迭代器
Iterator<Map.Entry<Integer,String>> it = set.iterator();
while (it.hasNext()){
Map.Entry<Integer,String> node = it.next();
Integer key = node.getKey();
String value = node.getValue();
System.out.println(key + "=" + value );
}
foreach:
- 这种方式效率比较高,因为获取key和value都是直接从node对象中获取的属性值
- 这种方式比较适合大数据
Set<Map.Entry<Integer,String>> set = map.entrySet();
for (Map.Entry<Integer,String> node: set){
System.out.println(node.getKey() + "--->" + node.getValue());
}
二、HashMap集合
HashMap集合底层是哈希表/散列表的数据结构。
在JDK8之后,如果哈希表单向链表中元素超过8个,单向链表这种数据结构会变成红黑树数据结构。当红黑树上的节点数量小于6时,会重新把红黑树变成单向链表数据结构。
这种方式也是为了提高检索效率,二叉树的检索会再次缩小扫描范围。提高效率。
1、哈希表
哈希表是一个怎样的数据结构?
是一个一维数组,这个数组中每一个元素是一个单向链表。(数组和链表的结合体)
哈希表是一个数组和单向链表的结合体
- 数组:在查询方面效率很高,随机增删效率很低。
- 单向链表:在随机增删方面效率很高,在查询方面效率很低
- 哈希表将以上的两种数据结构融合在一起,充分发挥了它们各自的优点。
对于哈希表数据结构来说:
- 如果o1和o2的hash值相同,一定是放到同一个单向链表上。
- 当然如果o1和o2的hash值不相同,但由于哈希算法执行结束之后转换的数组下标可能相同,此时会发生“哈希碰撞”
2、HashMap集合底层的源代码
public class HashMap{
//HashMap底层实际上就是一个数组。(一维数组)
Node<K,V>[] table;
//静态的内部类HashMap.Node
static class Node<K,V>{
final int hash;//哈希值(哈希值是key的hashCode()方法的执行结果。hash值通过哈希函数,可以转换成数组的下标)
final K ley; //存储到Map集合中的那个key
V value;//存储到Map集合中的那个value
Node<K,V> next;//下一个节点的内存地址
}
}
HashMap
为什么哈希表的随机增删,以及查询效率都很高?
增删是在链表上完成的。
查询也不需要都扫描,只需要部分扫描。
3、HashMap集合的key特点
无序不可重复
- 为什么无序? 因为不一定挂在哪个单向链表上。
- 不可重复是怎么保证的?
equals()
方法来保证HashMap集合的key
不可重复。如果key
重复了,value
会覆盖。
放在HashMap集合key
部分的元素其实就是放到HashSet集合中了。
所以HashSet集合中的元素也需要同时重写hashCode()
+equals()
方法
4、哈希表HashMap使用不当时无法发挥性能
假设将所有的hashCode()
方法返回值固定为某个值,那么会导致底层哈希表变成了纯单向链表。这种情况我们称为:散列分布不均匀
什么实际散列分布均匀?
假设有100个元素,10个单向链表,那么每个单向链表上有10个节点,这是最好的,是散列分布均匀的。
假设将所有的hashCode()方法返回值都设定为不一样的值,可以吗?
不可以,因为这样的话导致底层哈希表就变成了一维数组了,没有链表的概念了。也是散列分布不均匀。
5、必须同时重写hashCode和equals方法
放在HashMap集合key
部分的元素,以及放在HashSet集合中的元素,需要同时重写hashCode和equals方法
并且 equals() 方法返回如果是true,hasCode() 方法返回的值必须一样
6、HashMap集合容量
HashMap集合的默认初始化容量是16,默认加载因子是0.75
这个默认加载因子是当HashMap集合底层数组的容量达到75%的时候,数组开始扩容。
重点:HashMap集合的初始化容量必须是2的倍数,这也是官方推荐的,这是因为达到散列均匀,为了提高HashMap集合的存取效率,所必需的。
7、HashMap集合key允许为null
注意:但是HashMap集合的key
,null
只能有一个
三、HashMap和Hashtable的区别
Hashtable的key
和value
都是不能为null的。
HashMap集合的key
和value
都是可以为null的。
Hashtable集合初始化容量是11,集合扩容是:原容量*2+1
四、TreeMap集合
TreeMap集合底层实际上是一个二叉树。
五、Properties类
Properties是一个Map集合,继承Hashtable,Properties的key
和value
都是String
类型;
Properties被称为属性类对象;
Properties是线程安全的。
import java.util.Properties;
public class PropertiesText {
public static void main(String[] args) {
//创建一个Properties对象
Properties pro = new Properties();
//需要掌握Properties的两个方法,一个存,一个取
pro.setProperty("url","jdbc:mysql://localhost:3306/bjpowernode");
pro.setProperty("driver","com.mysql.jdbc.Driver");
pro.setProperty("username","root");
pro.setProperty("password","123");
//通过key获取value
String url = pro.getProperty("url");
String driver = pro.getProperty("driver");
String username = pro.getProperty("username") ;
String password = pro.getProperty("password");
System.out.println(url);
System.out.println(driver);
System.out.println(username);
System.out.println(password);
}
}