由于上一篇文章的篇幅实在太长了,讲的都是单列集合,这篇文章将单独介绍双列集合Map的使用.
Map双列集合根接口
如果程序中存储了几百万个学生,而且经常需要使用学号来搜索某个学生,那么这个需求有效的数据结构就是Map。Map是一种依照键(key)存储元素的容器,键(key)很像下标,在List中下标是整数。在Map中键(key)可以使任意类型的对象。Map中不能有重复的键(Key),每个键(key)都有一个对应的值(value)。一个键(key)和它对应的值构成map集合中的一个元素。
Map中的元素是两个对象,一个对象作为键,一个对象作为值。键唯一、值可重复(新值覆盖旧值)。
Map接口的共性方法
操作 | 含义 | 返回值 |
---|---|---|
put(K key, V value) | 存储元素的时候,当key相同时,则添加失败,但是添加的value值会覆盖被替换的值,并且会返回那个被替换的值,如果添加元素成功则返回 null。 | Object |
putAll(Map m) | 调用该方法是将另一个map集合的元素添加到当前集合中。 | void |
remove(Object key) | 根据该键删除其值并返回该调用者 | Object |
clear() | 清空集合对象 | void |
get(key) | 根据键获取其值 | Object |
size() | 获取长度 | int |
values() | 获取map集合的所有值并返回一个Collection集合中 | Collection |
isEmpty() | 长度为0返回true否则false | boolean |
containsKey(Object key) | 判断集合中是否包含指定的key | boolean |
containsValue(Object value) | 判断集合中是否包含指定的value | boolean |
相同key替换value的示例
public class _Main44 {
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<Integer,String>();
map.put(1, "a");
map.put(2, "b");
map.put(3, "c");
map.put(4, "d");
//key相同,value不同,返回的是被替换的那个Value
System.out.println(map.put(1, "g"));
System.out.println(map);
//将map中所有的value提取并返回到Collection集合中
Collection<String> c = map.values();
System.out.println(c);
}
}
运行结果:
Map集合的遍历
注意在Map体系的集合中,是没有Iterator迭代器可用,所以Map集合有自己的迭代方式。
1、Set keySet():该方法返回的是Map集合中的所有键,并存储到Set集合中。
2、Set entrySet() :获取Map集合中的所有键值对(关系)并返回到一个Set集合中。
通过keySet迭代Map集合
步骤:
1.调用map接口的keySet方法,获取map集合中的所有键,并存储到Set集合中。
2.通过Set接口的iterator方法创建迭代器,遍历Set集合中所存储的键值。
3.在遍历的过程中通过Map集合的get方法,获取对应键的值。
class Demo1 {
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("张三", "小红");
map.put("李四", "小兰");
map.put("王五", "小花");
// 通过keySet方法获取map集合的键和值
Set<String> keys = map.keySet();
// 使用Set集合的iterator方法创建迭代器对象
Iterator<String> it = keys.iterator();
while (it.hasNext()) {
// 通过迭代逐个获取Set集合中锁存储的键
String key = it.next();
// 通过map集合的get方法获取对应键的值
System.out.println("键:" + key + " 值:" + map.get(key));
}
}
}
运行结果:
通过entrySet迭代Map集合
步骤:
1.调用Map集合的entrySet方法,获取所有的键值对并返回到Set集合中
2.创建Set集合的迭代器,遍历Set集合中的所有键值对(关系)对象
3.在遍历键值对的时候,通过键值对对象调用Entry接口的特有方法getKey()和getValue()获取分别获取Map结合的键和值。
public class Demo1 {
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("张三", "小红");
map.put("李四", "小兰");
map.put("王五", "小花");
// 调用entrySet方法获取键值对并存储到Set集合中
Set<Map.Entry<String, String>> entries = map.entrySet();
// 通过Set集合创建迭代器
Iterator<Map.Entry<String, String>> iterator = entries.iterator();
while (iterator.hasNext()) {
// 迭代取出Set集合中的所有键值对(关系)返回的是Entry接口类型
Map.Entry<String, String> entry = iterator.next();
// 通过方法getValue得到键值
String values = entry.getValue();
// 通过方法getKey得到键
String keys = entry.getKey();
System.out.println("键:" + keys + " 值:" + values);
}
}
}
运行结果:
Map接口的内部接口Entry
在Map接口的内部还定义了一个Entry接口,该接口特有方法如下:
1.boolean equals(Object o)
比较指定对象与此项的相等性。
2.K getKey()
返回与此项对应的键。
3. V getValue()
返回与此项对应的值。
4.int hashCode()
返回此映射项的哈希码值。
5.V setValue(V value)
用指定的值替换与此项对应的值(可选操作)。
HashMap集合类
底层是哈希表数据结构,线程是不同步的,可以存入null键,null值。要保证键的唯一性,需要覆盖hashCode方法,和equals方法。元素是不可重复、无存储顺序的
HashMap的存储原理
HashMap存储元素的方式是无序的,原理和HashSet集合一样。
往HashMap存储元素的时候,首先会调用键的hashCode得到元素的哈希码值,然后算出该数据在哈希表中的存储位置。
情况1:根据键的哈希码算出的位置目前没有任何元素存储,那么该元素可以直接添加。
情况2: 根据键的哈希码算出的位置目前已经有了其他元素存储了,那么还会调用键的的equals方法再与这个位置的元素再比较一次。如果equals方法返回的是true,那么该元素不允许被添加,如果equals方法返回的是false,那么该元素允许添加。
TreeMap集合类
可以对键进行自然排序,存储是无序,键是有排序的。底层是二叉树数据结构。可以对map集合中的键进行排序。需要实现Comparable接口复写 compareTo方法或者自定义类实现Comparator接口,创建比较器来对键值进行比较排序。return 0,来判断键的唯一性。
TreeMap的排序,TreeMap可以对集合中的键进行排序。如何实现键的排序?
方式一:元素自身具备比较性(自然排序)
和TreeSet一样原理,需要让存储在键位置的对象实现Comparable接口,重写compareTo方法,也就是让元素自身具备比较性,这种方式叫做元素的自然排序也叫做默认排序。
方式二:容器具备比较性
当元素自身不具备比较性,或者自身具备的比较性不是所需要的。那么此时可以让容器自身具备。需要定义一个类实现接口Comparator,重写compare方法,并将该接口的子类实例对象作为参数传递给TreeMap集合的构造方法。
注意:当Comparable比较方式和Comparator比较方式同时存在时,以Comparator的比较方式为主;
注意:在重写compareTo或者compare方法时,必须要明确比较的主要条件相等时要比较次要条件。(假设姓名和年龄一致的人为相同的人,如果想要对人按照年龄的大小来排序,如果年龄相同的人,需要如何处理?不能直接return 0,因为可能姓名不同(年龄相同姓名不同的人是不同的人)。此时就需要进行次要条件判断(需要判断姓名),只有姓名和年龄同时相等的才可以返回0.)
TreeMap的存储原理
原理和TreeSet类似
1. 往TreeMap添加元素的时候,如果元素的键是具备自然顺序的特性,那么会根据键的自然顺序进行排序存储。
2. 往TreeMap添加元素的时候,如果数据的键不具备自然顺序的特性,那么键所属的类必须要实现Comparable接口。把比较的规则定义在CompareTo方法中。
3. 往TreeMap添加元素的时候,如果数据的键不具备自然顺序的特性,而且键所属的类没有实现Comparable接口,那么可以在创建TreeMap对象的时候传入一个比较器对象。
注意:
Set集合是元素不可重复,Map是键不可重复.
如果存入重复元素如何处理?
Set的重复元素不能存入,add方法返回false
Map的重复键将覆盖旧键,put方法返回旧键对应的值。
自定义TreeMap的排序规则
还是上一篇文章的比较器
/**
* 自定义一个比较器类,通过id
*
* @author mChenys
*
*/
public class MyComparator implements Comparator {
/**
* Compare方法中就写两个元素比较的规则。
* 如果o1小于o2,返回一个负数;如果o1大于o2,返回一个正数;如果他们相等,则返回0;
*/
public int compare(Object o1, Object o2) {
if (o1 instanceof Emp && o2 instanceof Emp) {
Emp e1 = (Emp) o1;
Emp e2 = (Emp) o2;
return e1.id - e2.id;
}
return 0;
}
}
排序操作
/**
* 对TreeMap集合的key进行按Emp的id进行排序
* @author mChenys
*
*/
public class TreeMapSort {
public static void main(String[] args) {
MyComparator comparator = new MyComparator();
TreeMap<Emp, Integer> map = new TreeMap<Emp, Integer>(comparator);
map.put(new Emp(117, "哈哈", 3000), 1);
map.put(new Emp(222, "呵呵", 1000), 2);
map.put(new Emp(250, "嘻嘻", 500), 3);
map.put(new Emp(300, "吼吼", 2000), 4);
System.out.println("集合的元素是:" + map);
}
}
运行结果:
集合工具类Collections
常用方法
1,对list集合进行排序。
sort(list);
sort(list,comaprator);
2, 对list进行二分查找,返回索引位置:
int binarySearch(list,key);
int binarySearch(list,key,Comparator);
3,对集合取最大值或者最小值。
max(Collection)
max(Collection,comparator)
min(Collection)
min(Collection,comparator)
4,对list集合进行反转。 对集合中的元素进行翻转。
reverse(list);
5,对比较方式进行强行逆转。
Comparator reverseOrder();
Comparator reverseOrder(Comparator);
6,对list集合中的元素进行位置的置换。
swap(list,x,y);
7,对list集合进行元素的替换。如果被替换的元素不存在,那么原集合不变。
replaceAll(list,old,new);
8,可以将不同步的集合变成同步的集合。
Set synchronizedSet(Set s)
Map synchronizedMap(Map m)
List synchronizedList(List list)