双列集合Map及其子类
Map集合
Map集合是所有双列集合的祖宗类,所谓双列集合,即集合中的一个元素由两部分组成,分别是键和值,也叫键值对。Map集合中的元素以键值对的形式存储,每一个键对应着一个值,并且集合中键不能重复,但值可以重复
- 应用场景
- 当我们开发中遇到两两对应的数据就可以使用Map集合存储,如一部手机对应一个价格、一个城市对应一个天气等等…
- 常用方法
方法 | 作用 |
---|---|
put(K key, V value) | 添加元素 |
size() | 获取集合大小 |
isEmpty() | 判断集合是否为空,为空就返回true,反之返回false |
get(Object key) | 根据键获取对应的值 |
remove(Object key) | 根据键删除整个元素 |
containsKey(Object key) | 判断集合中是否包含某个键 |
containsValue(Object value) | 判断集合中是否包含某个值 |
Set<K> keySet() | 获取全部键的集合 |
Collection<V> values() | 获取Map集合的全部值 |
putAll(Map<? extends K, ? extends V> list) | 把一个集合添加到另一个集合中 |
clear() | 清空集合 |
public class Demo01 {
public static void main(String[] args) {
Map<String,Integer> list = new HashMap();
// put(K key, V value) 添加元素
list.put("石昊",24);
list.put("叶凡",21);
list.put("楚风",18);
// size() 获取集合大小
int size = list.size();
System.out.println(size);
// isEmpty() 判断集合是否为空,为空就返回true,反之返回false
boolean empty = list.isEmpty();
System.out.println(empty);
// get(Object key) 根据键获取对应的值
Integer age = list.get("石昊");
System.out.println("石昊:"+age);
// remove(Object key) 根据键删除整个元素
list.remove("楚风");
System.out.println(list);
// containsKey(Object key) 判断集合中是否包含某个键
boolean isName = list.containsKey("叶凡");
System.out.println(isName);
// containsValue(Object value) 判断集合中是否包含某个值
boolean isAge = list.containsValue(99);
System.out.println(isAge);
// Set<K> keySet() 获取全部键的集合
Set<String> keySet = list.keySet();
System.out.println(keySet);
// Collection<V> values() 获取Map集合的全部值
Collection<Integer> values = list.values();
System.out.println(values);
// putAll(Map<? extends K, ? extends V> list) 把一个集合添加到另一个集合中
Map<String,Integer> temp = new HashMap<>();
temp.putAll(list);
System.out.println(temp);
// clear() 清空集合
list.clear();
System.out.println(list);
}
}
- Map集合的遍历方式
键找值
- 通过keySet()方法获取集合中所有的键并保存到一个Set集合中
- 通过增强for循环的方式遍历这个Set集合,拿到每一个key,再通过Map集合中的get()方法拿到这个键所对应的值完成遍历
public class Demo02 {
public static void main(String[] args) {
Map<String,Integer> list = new HashMap<>();
list.put("草加",19);
list.put("乾巧",17);
list.put("真司",21);
Set<String> keySet = list.keySet();
for (String key : keySet) {
System.out.println(key+"->"+list.get(key));
}
}
}
键值对(难度较大)
- 调用Map集合中的entrySet()方法,获取一个键值对类型的Set集合
- 通过增强for循环遍历,调用getKey()和getValue()方法获取对应的键和值完成遍历
public class Demo02 {
public static void main(String[] args) {
Map<String,Integer> list = new HashMap<>();
list.put("草加",19);
list.put("乾巧",17);
list.put("真司",21);
Set<Map.Entry<String, Integer>> entries = list.entrySet();
for (Map.Entry<String, Integer> entry : entries) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+"->"+value);
}
}
}
Lambda(非常简单)
- 直接使用
forEach((k, v) -> {代码})
的格式遍历即可
public class Demo02 {
public static void main(String[] args) {
Map<String,Integer> list = new HashMap<>();
list.put("草加",19);
list.put("乾巧",17);
list.put("真司",21);
list.forEach((k,v) -> System.out.println(k+"->"+v));
}
}
HashMap集合
HashMap集合是Map接口下的一个实现类,有
无序、不重复、无索引
的特点,这些特点都是根据键来实现的,和其对应的值无关。HashSet集合的底层其实就是使用HashMap来实现的,只是HashSet是HashMap中的键,不取其值,索引HashMap底层也是基于哈希表实现的,JDK8之前哈希表由数组+链表
组成,JDK8开始哈希表由数组+链表+红黑树
组成
- HashMap集合中添加元素的步骤
- 先判断底层动态数组是否为null,如果为null就进行扩容操作
- 根据元素的键计算出hash值得到插入数组的索引,找到数组中该索引的位置
- 如果该位置上没有元素存在,就新建头结点插入
- 如果该位置上有元素存在,就判断此位置上的是链表还是红黑树
- 如果该索引处是链表,遍历链表,如果发现链表中的键和插入元素的键相同,就直接覆盖链表中的相同键的值,这里说的相同是hashCode和equals比较后的相同
- 如果不同,就直接在链表的末尾插入该元素,然后判断链表长度是否大于8,大于8的话要把链表转化成红黑树
- 如果该索引处是红黑树,则遍历红黑树,如果发现有结点上的键和插入元素的键相同,就覆盖结点上的值
- 如果不同就在树的合适位置插入该元素
- HashMap集合的特点
- 增删改查数据的性能都不错
LinkedHashMap集合
LInkedMap是HashMap集合的子类,集合中的元素具有
有序、不重复、无索引
的特点,所有特点都由键的特性决定
- 底层原理
- LinkedHashMap的底层原理是基于哈希表和双链表实现
- 其实LInkedHashSet集合的底层的基于LInkedHashMap实现的,LInkedHashMap的值就是LInkedHashMap的键
TreeMap集合
TreeMap集合是Map集合的子类,其元素按照键具有
不重复、无索引、可排序(按照大小默认升序)
- 底层原理
- TreeMap集合底层是基于红黑树实现的,增删除查的性能良好
- 其实TreeSet的底层是基于TreeMap实现的,TreeSet的值就是TreeMap的键
- TreeMap的排序方式
注意:TreeMap里面是根据排序的属性来确定唯一值的,也就是说,用来排序的属性值要是相同了,TreeMap就会把旧的value给覆盖掉,如下:
方式一:让类实现Compareble接口,重写里面的comparaTo方法制定规则
public class Demo03 {
public static void main(String[] args) {
TreeMap<Student,String> list = new TreeMap<>();
list.put(new Student("刘备",23),"蜀国");
list.put(new Student("曹操",33),"魏国");
list.put(new Student("孙权",21),"吴国");
list.forEach((k,v) -> System.out.println(k+"->"+v));
}
}
class Student implements Comparable<Student> {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
@Override
public int compareTo(Student o) {
return this.getAge() - o.getAge();
}
}
方式二:通过调用TreeSet集合的有参构造器,可以设置Comparator对象(比较器对象,用于制定比较
public class Demo03 {
public static void main(String[] args) {
TreeMap<Student,String> list = new TreeMap<>((o1, o2) -> o1.getAge() - o2.getAge());
list.put(new Student("刘备",21),"蜀国");
list.put(new Student("曹操",33),"魏国");
list.put(new Student("孙权",24),"吴国");
list.forEach((k,v) -> System.out.println(k+"->"+v));
}
}
class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}