一、数据结构
集合类框架
2、集合类和数组的区别
二、HashMap
HashMap的特点
数组的特点:查询效率高,插入,删除效率低。
链表的特点:查询效率低,插入删除效率高。
2. HashMap的数据结构
在HashMap底层使用数组加(链表或红黑树)的结构完美的解决了数组和链表的问题,使得查询和插入,删除的效率都很高。
java1.7 之前是数组+链表 ,之后是 数组+链表+红黑树
HashMap存储元素的过程
public class Test {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("Tom", 100);//向HashMap中添加元素
}
}
第一步:计算出键“Tom”的hashcode,该值用来定位要将这个元素存放到数组中的什么位置.
什么是hashcode?
在Object类中有一个方法:
public native int hashCode();
该方法用native修饰,所以是一个本地方法,所谓本地方法就是非java代码,这个代码通常用c或c++写成,在java中可以去调用它。
调用这个方法会生成一个int型的整数,我们叫它哈希码,哈希码和调用它的对象地址和内容有关.
哈希码的特点是:
对于同一个对象如果没有被修改(使用equals比较返回true)那么无论何时它的hashcode值都是相同的
对于两个对象如果他们的equals返回false,那么他们的hashcode值也有可能相等
第二步:Tom的hashcode为20977295 数组长度为 16则要存储在数组索引为 20977295%16=1的地方
第三步:分两种情况:
1. 数组索引为1的地方是空的,这种情况很简单,直接将元素放进去就好了。
2. 已经有元素占据了索引为1的位置,这种情况下我们需要判断一下该位置的元素和当前元素是否相等,使用equals来比较。
如果使用默认的规则是比较两个对象的地址。也就是两者需要是同一个对象才相等,当然我们也可以重写equals方法来实现我们自己的比较规则,最常见的是通过比较属性值来判断是否相等。如果两者相等则直接覆盖,如果不等则在原元素下面使用链表的结构存储该元素
每个元素节点都有一个next属性指向下一个节点,这里由数组结构变成了数组+链表结构,红黑树又是怎么回事呢?
因为链表中元素太多的时候会影响查找效率,所以当链表的元素个数达到8的时候使用链表存储就转变成了使用红黑树存储,原因就是红黑树是平衡二叉树,在查找性能方面比链表要高.
3.HashMap的扩容
了解hashMap的扩容,先来了解HashMap的几个重要参数
table变量:HashMap的底层数据结构,是Node类的实体数组,用于保存key-value对;
capacity:并不是一个成员变量,但却是一个必须要知道的概念,表示容量;
size变量:表示已存储的HashMap的key-value对的数量;
loadFactor变量:装载因子,用于衡量满的程度;
threshold变量:临界值,当超出该值时,表示table表示该扩容了;
put方法
HashMap使用哈希算法得到数组中保存的位置,然后调用put方法将key-value对保存到table变量中。我们通过图来演示一下存储的过程。
解释一下:
1)通过hash(Object key)算法得到hash值;
2)判断table是否为null或者长度为0,如果是执行resize()进行扩容;
3)通过hash值以及table数组长度得到插入的数组索引i,判断数组table[i]是否为空或为null;
4)如果table[i] == null,直接新建节点添加,转向 8),如果table[i]不为空,转向 5);
5)判断table[i]的首个元素是否和key一样,如果相同直接覆盖value,这里的相同指的是hashCode以及equals,否则转向 6);
6)判断table[i] 是否为treeNode,即table[i] 是否是红黑树,如果是红黑树,则直接在树中插入键值对,否则转7);
7)遍历table[i],判断链表长度是否大于8,大于8的话把链表转换为红黑树,在红黑树中执行插入操作,否则进行链表的插入操作;遍历过程中若发现key已经存在直接覆盖value即可;
8)插入成功后,判断实际存在的键值对数量size是否超多了最大容量threshold,如果超过,进行扩容。
三、HashMap的常用方法
①.put(K key, V value) 将键(key)/值(value)映射存放到Map集合中
public class Test {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("Tom", 100);//向HashMap中添加元素
}
}
②.get(Object key) 返回指定键所映射的值,没有该key对应的值则返回 null,即获取key对应的value。
public class Test {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("Tom", 100);
map.put("Tom", 0);
int score = map.get("Tom");// 获取key对应的value
System.out.println(score);// key不允许重复,若重复,则覆盖已有key的value
}
}
可知,之前加入的value已被覆盖,前面的观点得证
③. size() 返回Map集合中数据数量,准确说是返回key-value的组数。
public class Test {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("Tom", 100);
map.put("Jim", 90);
map.put("Sam", 91);
System.out.println(map.size());
}
}
④:clear() 清空Map集合
public class Test {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("Tom", 100);
map.put("Jim", 90);
map.put("Sam", 91);
map.clear();// 清空map中的key-value
System.out.println(map.size());
}
}
⑤:isEmpty () 判断Map集合中是否有数据,如果没有则返回true,否则返回false
public class Test {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("Tom", 100);
map.put("Jim", 90);
map.put("Sam", 91);
map.clear();// 清空map中的key-value
System.out.println(map.isEmpty());
}
}
⑥:remove(Object key) 删除Map集合中键为key的数据并返回其所对应value值。
public class Test {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("Tom", 100);
map.put("Jim", 90);
map.put("Sam", 91);
map.remove("Tom");
System.out.println(map);
}
}
⑦:containsKey(Object key) Hashmap判断是否含有key
public class Test {
public static void main(String[] args) {
HashMap<String, Integer> map=new HashMap<>();
/*boolean*///判断map中是否存在这个key
System.out.println(map.containsKey("DEMO"));//false
map.put("DEMO", 1);
System.out.println(map.containsKey("DEMO"));//true
}
}
⑧:containsValue(Object value) Hashmap判断是否含有value:
public class Test {
public static void main(String[] args) {
HashMap<String, Integer> map=new HashMap<>();
/*boolean*///判断map中是否存在这个value
System.out.println(map.containsValue(1));//false
map.put("DEMO", 1);
System.out.println(map.containsValue(1));//true
}
}
⑨:Hashmap添加另一个同一类型的map下的所有数据
public class Test {
public static void main(String[] args) {
HashMap<String, Integer> map=new HashMap<>();
HashMap<String, Integer> map1=new HashMap<>();
/*void*///将同一类型的map添加到另一个map中
map1.put("DEMO1", 1);
map.put("DEMO2", 2);
System.out.println(map);//{DEMO2=2}
map.putAll(map1);
System.out.println(map);//{DEMO1=1, DEMO2=2}
}
}
⑩:Hashmap替换这个key的value
public class Test {
public static void main(String[] args) {
HashMap<String, Integer> map=new HashMap<>();
/*value*///判断map中是否存在这个key
map.put("DEMO1", 1);
map.put("DEMO2", 2);
System.out.println(map);//{DEMO1=1, DEMO2=2}
System.out.println(map.replace("DEMO2", 1));//2
System.out.println(map);//{DEMO1=1, DEMO2=1}
}
}