集合Map
有一种数据比较常见,比如一个学号对应一个学生,这种键值映射关系的数据,为了方便操作,给我们提供了另一种容器,叫做Map:称之为双列集合,有键 有映射值,一个键只能映射一个值,键是唯一的,如果键相同,那么值会覆盖。
所有的双列集合的数据结构,只跟键有关,跟值没有关系。
Map接口和Collection接口的不同:
Map是双列的,Collection是单列的;
Map的键唯一,Collection的子体系Set是唯一的;
Map集合的数据结构针对键有效,跟值无关;Collection集合的数据结构是针对元素有效。
接口Map<K,V>
K-此映射所维护的键的类型
V-映射值类型
实现类 HashMap<K,V> 、Hashtable<K,V>、 LinkedHashMap<K,V> 、 TreeMap<K,V>
1.HashMap<K,V>
键的数据结构是哈希表,所以键无序且唯一。允许null值 null键。线程不安全,效率高。所有的双列集合的数据结构,只跟键有关,跟值没有关系。当键相同,值就覆盖,返回的是上一次这个键所映射的那个旧值。
hm.put(“ K key”,“ V value”); 添加功能,这个其实还有另一个功能:替换—
如果键是第一次存储,就直接存储元素,返回null;
如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值
hm.clear(); 清空
hm.remove(K); 根据键值删除,返回值是键所对应的值
hm.size(); 集合长度
判断相关:
判断是否有某个键 hm.containsKey(K);
判断是否有某个值 hm.containsValue(V);
通过键获取值 hm.get(K); 如果没有这个键返回null
通过键获取值 hm.getOrDefault(K,备用V); 如果没有这个键返回备用值
判断是否为空 hm.isEmpty();
hm.values(); 获取所有值得集合 放入collection
public static void main(String[] args) {
HashMap<String, String> hm = new HashMap<>();
hm.put("米兰", "马尔蒂尼");
hm.put("国米", "萨内蒂");
hm.put("尤文", "皮耶罗");
hm.put("罗马", "托蒂");
// hm.clear();清空集合
// hm.size() 集合的长度
System.out.println(hm.size());
// 返回的是那个键,所对应的值。
String s = hm.remove("罗马");
System.out.println(hm);
System.out.println(s);
System.out.println(hm.containsKey("佛罗伦萨"));// false
System.out.println(hm.containsValue("马尔蒂尼"));// true
System.out.println(hm.isEmpty());// false
//通过键来获取值
System.out.println(hm.get("国米"));// 萨内蒂
//通过键来获取值,没有对应的值,可以给一个默认值。
System.out.println(hm.getOrDefault("佛罗伦萨", "巴蒂斯图塔"));// 巴蒂斯图塔
}
遍历双链集合
方式一:按照键找值,拿出所有键放入set集合,hm.keySet(); 获取所有键的集合,最后hm.get(K)按键找值。
方式二:将键值对,看作一个整体,把键值对 对象获取出来,然后使用键值对,对象中的方法获取键和值。
Map.Entry<String, String> ,K getKey () 返回与此项对应的键。 V getValue () 返回与此项对应的值。
方法三:forEach();
public static void main(String[] args) {
HashMap<String, String> hm = new HashMap<>();
hm.put("皇马", "BBC");
hm.put("巴萨", "MSN");
hm.put("拜仁", "罗贝里");
hm.put("曼联", "林加德");
// values();获取所有值的集合
Collection<String> values = hm.values();
System.out.println(values);
// 遍历双列集合
// 第一种:键找值 keySet();获取所有键的集合
Set<String> keySet = hm.keySet();
for (String key : keySet) {
String value = hm.get(key);//按照键找值
System.out.println(key + "===" + value);
}
System.out.println("=====================================");
//第二种:把键值对,看做一个整体,把键值对,对象获取出来,然后使用键值对,对象中的方法来获取键和值。
Set<Map.Entry<String, String>> entries = hm.entrySet();
for (Map.Entry<String, String> entry : entries) {
//System.out.println(entry);
String key = entry.getKey();// 返回与此项对应的键
String value = entry.getValue();// 返回与此项对应的值
System.out.println(key + "===" + value);
}
//方法三:
System.out.println("================================");
hm.forEach(new BiConsumer<String, String>() {
@Override
public void accept(String key, String value) {
System.out.println(key + "===" + value);
}
});
}
所有的双列集合的数据结构,只跟键有关,跟值没有关系。
理解:new student虽然设置的成员变量name、age相同,但是两个都可以存进去,没有重写equales()和hashcode()方法,比较就认为地址值不同。
public static void main(String[] args) {
// 存储键是Student类型,值是String类型
HashMap<Student, String> hm = new HashMap<>();
hm.put(new Student("张三", 23),"s001" );
hm.put(new Student("张三", 23),"s001" );
hm.put(new Student("王五", 25),"s002" );
hm.put(new Student("赵六", 26),"s003" );
hm.put(new Student("田七", 27),"s004" );
for (Map.Entry<Student, String> entry : hm.entrySet()) {
Student key = entry.getKey();
String value = entry.getValue();
System.out.println(key.getName()+"#"+key.getAge()+"===="+value);
}
}
2.Hashtable<K,V>
和HashMap<K,V>的区别:
Hashtable<K,V> 不允许null值 和 null键,线程安全,效率低。
public static void main(String[] args) {
HashMap<String, String> stringStringHashMap = new HashMap<>();
stringStringHashMap.put(null,null);
System.out.println(stringStringHashMap);
Hashtable<String, String> stringStringHashtable = new Hashtable<>();
//stringStringHashtable.put(null,"abc");
stringStringHashtable.put("abc", null);//NullPointerException
}
3.LinkedHashMap<K,V>
键的数据结构是链表和哈希表,键唯一且有序,链表保证有序,哈希表保证唯一。
public static void main(String[] args) {
// LinkedHashMap 键的数据结构是链表和哈希表,键唯一且有序,链表保证有序,哈希表保证唯一。
LinkedHashMap<String, String> hm = new LinkedHashMap<>();
hm.put("拜仁", "莱万");
hm.put("拜仁","克洛泽");
hm.put("多特", "哈兰德");
hm.put("莱比锡", "维尔纳");
hm.put("勒沃库森", "哈佛茨");
System.out.println(hm);
// {拜仁=克洛泽, 多特=哈兰德, 莱比锡=维尔纳, 勒沃库森=哈佛茨}
}
4.TreeMap<K,V>
TreeMap 键不允许插入null, 键的数据结构是红黑树,可保证键的排序和唯一性,排序分为自然排序和比较器排序 , 线程是不安全的效率比较高。
public static void main(String[] args) {
TreeMap<Integer, String> treeMap = new TreeMap<>();
treeMap.put(7, "舍甫琴科");
treeMap.put(3, "马尔蒂尼");
treeMap.put(1, "迪达");
treeMap.put(21, "皮尔洛");
treeMap.put(10, "鲁伊科斯塔");
treeMap.put(9, "因扎吉");
treeMap.put(2, "卡福");
treeMap.put(13, "内斯塔");
treeMap.put(5, "科斯塔库塔");
treeMap.put(8, "加图索");
Set<Integer> integers = treeMap.keySet();
for (Integer integer : integers) {
System.out.println(integer+"-"+treeMap.get(integer));
}
System.out.println();
TreeMap<String, Integer> Milan = new TreeMap<>();
Milan.put("Shevchenko",7);
Milan.put("KaKa",22);
Milan.put("Cafu",2);
Milan.put("Gattuso",8);
Milan.put("Nesta",13);
Milan.put("Tomasson",15);
Milan.put("Costa",10);
Set<Map.Entry<String, Integer>> entries = Milan.entrySet();
for (Map.Entry<String, Integer> entry : entries) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key +"-"+ value);
}
}
自然排序
public static void main(String[] args) {
// 键是Student类型,值是String类型
// 按照学生的年龄大小来排序
TreeMap<Student, String> treeMap = new TreeMap<>();
treeMap.put(new Student("张国荣", 18), "s001");
treeMap.put(new Student("张国荣", 18), "s001");
treeMap.put(new Student("张世豪", 15), "s004");
treeMap.put(new Student("张世荣", 17), "s002");
treeMap.put(new Student("张学友", 18), "s003");
treeMap.put(new Student("张三", 18), "s004");
treeMap.put(new Student("张曼玉", 17), "s005");
/* System.out.println(treeMap); */
treeMap.forEach(new BiConsumer<Student, String>() {
@Override
public void accept(Student student, String s) {
System.out.println(student.getName()+"=="+student.getAge()+"========="+s);
}
});
}
@Override
public int compareTo(Student o) {
int num=this.age-o.age==0?this.name.compareTo(o.name):this.age-o.age;
return num;
}
比较器排序
public static void main(String[] args) {
TreeMap<Student, String> treeMap = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s1.getAge() - s2.getAge() == 0 ? s1.getName().compareTo(s2.getName()) : s1.getAge() - s2.getAge();
return num;
}
});
treeMap.put(new Student("张国荣", 18), "s001");
treeMap.put(new Student("张国荣", 18), "s001");
treeMap.put(new Student("张世豪", 15), "s004");
treeMap.put(new Student("张世荣", 17), "s002");
treeMap.put(new Student("张学友", 18), "s003");
treeMap.put(new Student("张三", 18), "s004");
treeMap.put(new Student("张曼玉", 17), "s005");
// System.out.println(treeMap);
treeMap.forEach(new BiConsumer<Student, String>() {
@Override
public void accept(Student student, String s) {
System.out.println(student.getName() + "==" + student.getAge() + "=========" + s);
}
});
}
练习1:
统计字符串中字符出现次数
“aababcabcdabcde”, 获取字符串中每一个字母出现的次数
要求结果:a(5) b(4) c(3) d(2) e(1)
a—5
b—4
c—3
d—2
e—1
每个字符和它出现的次数,是键值映射关系
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一段字符串");
String str = sc.nextLine();
// 每个字符和它出现的次数,是键值映射关系
HashMap<Character, Integer> hashMap = new HashMap<>();
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
if (!hashMap.containsKey(ch)) {
hashMap.put(ch, 1);
} else {
Integer value = hashMap.get(ch);
value++;
// 键相同,值覆盖
hashMap.put(ch, value);
}
}
System.out.println(hashMap);
// 遍历集合拼串
StringBuilder sb = new StringBuilder();
for (Map.Entry<Character, Integer> entry : hashMap.entrySet()) {
Character key = entry.getKey();
Integer value = entry.getValue();
sb.append(key).append("(").append(value).append(")").append(" ");
}
String s = sb.toString();
System.out.println(s);
练习2:集合嵌套 - - - 先看小的关系 再看大的关系
HashMap嵌套HashMap
public static void main(String[] args) {
/* *
基础班
张三 20
李四 22
就业班
王五 21
赵六 23
* */
//HashMap 嵌套 HashMap
HashMap<String, Integer> jcMap = new HashMap<>();
jcMap.put("张三",20);
jcMap.put("李四",22);
HashMap<String, Integer> jyMap = new HashMap<>();
jyMap.put("王五", 21);
jyMap.put("赵六", 23);
HashMap<String, HashMap<String, Integer>> maxMap = new HashMap<>();
maxMap.put("基础班",jcMap);
maxMap.put("就业班",jyMap);
Set<String> keySet = maxMap.keySet();
for (String s : keySet) {
System.out.println(s);
HashMap<String, Integer> minMap = maxMap.get(s);
Set<String> keySet1 = minMap.keySet();
for (String s1 : keySet1) {
System.out.println("\t" +s1+" "+ minMap.get(s1));
}
}
}
HashMap嵌套ArrayList
public static void main(String[] args) {
/* *
三国演义
吕布
周瑜
笑傲江湖
令狐冲
林平之
神雕侠侣
郭靖
杨过
* */
ArrayList<String> sgList = new ArrayList<>();
sgList.add("吕布");
sgList.add("周瑜");
ArrayList<String> xaList = new ArrayList<>();
xaList.add("令狐冲");
xaList.add("林平之");
ArrayList<String> sdList = new ArrayList<>();
sdList.add("郭靖");
sdList.add("杨过");
LinkedHashMap<String, ArrayList<String>> hashMap = new LinkedHashMap<>();
hashMap.put("三国演义", sgList);
hashMap.put("笑傲江湖", xaList);
hashMap.put("神雕侠侣", sdList);
Set<String> keySet = hashMap.keySet();
for (String s : keySet) {
System.out.println(s);
ArrayList<String> list = hashMap.get(s);
for (String s1 : list) {
System.out.println("\t" + s1);
}
System.out.println();
}
}
ArrayList嵌套HashMap
public static void main(String[] args) {
/*
周瑜-- - 小乔
吕布-- - 貂蝉
郭靖-- - 黄蓉
杨过-- - 小龙女
令狐冲-- - 任盈盈
林平之-- - 岳灵珊
*/
HashMap<String, String> sgMap = new HashMap<>();
sgMap.put("周瑜","小乔");
sgMap.put("吕布", "貂蝉");
HashMap<String, String> sdMap = new HashMap<>();
sdMap.put("郭靖", "黄蓉");
sdMap.put("杨过", "小龙女");
HashMap<String, String> xaMap = new HashMap<>();
xaMap.put("令狐冲", "任盈盈");
xaMap.put("林平之", "岳灵珊");
ArrayList<HashMap<String, String>> maxList = new ArrayList<>();
maxList.add(sgMap);
maxList.add(sdMap);
maxList.add(xaMap);
for (HashMap<String, String> minMap : maxList) {
Set<Map.Entry<String, String>> entries = minMap.entrySet();
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"------"+value);
}
System.out.println();
}
}