Java基础知识(二十九)集合(四)( Map接口的子类HashMap、TreeMap以及Collections工具类)

目录

一、Map接口

1、Map接口与Collection接口的区别:

2、Map接口的子类和方法

(1)各种功能:

(2)HashMap

(3)TreeMap

(4) LinkedHashMap

(5) HashMap与HashTable的区别:

3、集合的嵌套遍历

ArrayList嵌套TreeMap

二、Collections工具类

1、Collections与Collection的区别:

2、Collections中的方法


一、Map接口

概述:

将键映射到值的对象,Map不能包含重复的键,每个键最多包含一个值。

举例:

<K,V> 键值对:1001 小王;1002 小李 ; 1001 小周(这样是不允许的,小周会覆盖小王)。

Map集合中,K的值不可以重复,但V的值可以重复

1、Map接口与Collection接口的区别:

1、Map接口与Collection接口是平级关系,不存在继承关系,都是属于util包下面的。

2、Map集合中的元素都是成对出现的,Map中的键是唯一的,值是可以重复的,又称之为:夫妻对。Map的数据结构值针对键有效,跟值无关

3、Collection集合中的元素都是单独出现的,Collection接口下有个子接口Set,他的元素也是唯一的;List中的元素也是单独出现的,可以重复,像这样单独出现的元素,称之为:光棍。Collection集合的数据结构是针对元素有效

2、Map接口的子类和方法

(1)各种功能:

1、添加功能

V put(K key,V value) 将指定的值与该映射中的指定键相关联(可选操作)

举例:map.put(1001,"小王");

2、删除功能

void clear() 从该Map中删除所有的映射

V remove(Object key) 如果存在(可选的操作),从该Map中删除一个键的映射。

3、判断功能

boolean containsKey(Object key)如果此映射包含指定键的映射,则返回true。

boolean containsValue(Object value)如果此Map将一个或者多个键映射到指定的值,则返回true。

boolean isEmpty() 如果此Map不包含键值映射,则返回true。

4、获取功能

V get(Object key) 如果此映射包含该键的映射,返回到指定键所映射的值。或者null

Set(K) keySet()  返回此Map中包含的键的Set视图

Collection<V> values() 返回此Map中包含的值的Collection视图

Set<Map.Entry<K,V>>entrySet()  获取Map中所有的元素,元素的组成是一个键和一个值组成。

5、长度功能

int size() 返回此Map中键值映射的数量

添加、删除、判断与获取中的get()方法代码举例:

import java.util.HashMap;
import java.util.Map;
 
public class Demo1 {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
//        添加功能:
        map.put("小王","职员");
        map.put("小李","经理");
        map.put("小孙","销售");
        map.put("小周","财务");
        map.put("小王","总监");
        System.out.println("未做操作前的Map集合:"+map);
//        这里集合中总监覆盖了职员
//        删除功能:
        System.out.println(map.remove("小周"));
//        这里返回的是被删除的键所对应的值
        System.out.println("做删除后的Map集合:"+map);
//        map.clear();
//        判断功能:
        System.out.println(map.containsKey("小李"));
        System.out.println(map.containsValue("经理"));
        System.out.println(map.isEmpty());
//        获取功能:
        System.out.println(map.get("小王"));
//        获取一个不存在的键
        System.out.println(map.get("小赵"));
    }
}

输出结果: 

 

(2)HashMap

根据哈希表进行存储的,允许出现null键和null键,可以保证键的唯一性

Map获取功能具体代码举例:

这也是Map遍历集合的第一种方式:调用keySet方法通过键找值

import java.util.Collection;
import java.util.HashMap;
import java.util.Set;
 
public class Demo2 {
    public static void main(String[] args) {
        HashMap<String, String> map = new HashMap<>();
//        添加元素
        map.put("小王", "职员");
        map.put("小李", "经理");
        map.put("小孙", "销售");
        map.put("小周", "财务");
//        遍历集合
        Set<String> keySet = map.keySet();//获取键并用Set集合存放
        for (String keyvalue : keySet) {//遍历集合
            String value = map.get(keyvalue);//获取键对应的值
            System.out.println(keyvalue + ":" + value);
        }
        System.out.println("----------------------------------------");
//        返回包含值的Collection视图
        Collection<String> collection = map.values();
        for (String values : collection) {
            System.out.println(values);
        }
    }
}

输出结果:

这里对于返回包含值的Collection集合,只可返回值,不可以使用值去输出对应的键。

Set<Map.Entry<K,V>> entrySet()方法举例:

这是Map集合遍历的第二种方式:一次性获取所有的键值对,然后依次获取每一个键值对的键和值

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
 
public class Demo3 {
    public static void main(String[] args) {
        HashMap<String, String> map = new HashMap<>();
//        添加元素
        map.put("小王", "职员");
        map.put("小李", "经理");
        map.put("小孙", "销售");
        map.put("小周", "财务");
 
 
//        一次性获取所有的键值对
        Set<Map.Entry<String, String>> set = map.entrySet();
//        遍历集合获取每一个键值对
        for (Map.Entry<String, String> keyvalue : set){
            String key = keyvalue.getKey();
            String value = keyvalue.getValue();
            System.out.println(key+":"+value);
//            可以选择直接输出keyvalue,推荐使用上述方式
        }
    }
}

 输出结果:

Entry通过查看源码发现是一个抽象类,其中定义了getKey()和getValue()方法,并在某一个类中实现了这两种方法,所以可以使用这两种方法获取每一个键值对的键和值。

使用HashMap存储自定义对象

代码举例:

如果key是自己自定义的一个对象,该类需要重写hashCode()方法和equals()方法

因为put方法的底层,添加元素的标准就是根据hashCode()方法和equals()的值来判断元素是否重复

学生类:

import java.util.Objects;
 
public class Students {
    private String name;
    private int age;
 
    public Students() {
    }
 
    public Students(String name, int age) {
        this.name = name;
        this.age = age;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Students students = (Students) o;
        return age == students.age && Objects.equals(name, students.name);
    }
 
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
 
    @Override
    public String toString() {
        return "Student4{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

 测试类:

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
 
public class Demo7 {
    public static void main(String[] args) {
        //1、创建集合对象
        HashMap<Students, String> map = new HashMap<>();
 
        //2、创建学生对象
        Students s1 = new Students("王昭君", 17);
        Students s2 = new Students("貂蝉", 16);
        Students s3 = new Students("杨玉环", 18);
        Students s4 = new Students("西施", 19);
        Students s5 = new Students("王昭君", 17);
 
        //将元素添加到集合中
        map.put(s1, "1111");
        map.put(s2, "2222");
        map.put(s3, "3333");
        map.put(s4, "4444");
        map.put(s5, "5555");
 
        //遍历
        Set<Map.Entry<Students, String>> entries = map.entrySet();
        for (Map.Entry<Students, String> keyValue : entries) {
            Students key = keyValue.getKey();
            String value = keyValue.getValue();
            System.out.println(key + ":" + value);
        }
 
 
    }
}

输出结果:

(3)TreeMap

 TreeMap:键是基于红黑树结构存储的,可以保证键的唯一和排序

代码举例:TreeMap存储字符串并遍历

 
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
 
public class Demo4 {
    public static void main(String[] args) {
        TreeMap<String, String> map = new TreeMap<>();
//        添加元素
        map.put("Bill", "职员");
        map.put("Alan", "经理");
        map.put("John", "销售");
        map.put("Kate", "财务");
 
//        获取所有的键值对
        Set<Map.Entry<String, String>> entries = map.entrySet();
//        遍历
        for (Map.Entry<String, String> keyvalue : entries){
            String key = keyvalue.getKey();
            String value = keyvalue.getValue();
            System.out.println(key+":"+value);
        }
    }
}

 输出结果:

通过输出结果来看,TreeMap的输出是有序的。

TreeMap存储自定义对象并遍历:

若是仍然按照上面的写法会报错:ClassCastException: test.Test.src.com.tys.day20.Student cannot be cast to java.lang.Comparable

分析发现这是由于put方法在底层源码中需要向下转型,但是Student类中没有实现Comparable接口重写其中的CompareTo方法导致

解决办法:在Student类中实现Comparable接口并重写CompareTo方法即可,这里的CompareTo方法需要我们自己去重写方法体。

 正确代码如下:

这里推荐使用匿名内部类的形式实现Comparator接口重写CompareTo方法

Student类:

public class Student{
    private String name;
    private int age;
 
    public Student() {
    }
 
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }  
}

这里是测试类:

import java.util.Comparator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
 
public class Demo5 {
    public static void main(String[] args) {
        TreeMap<Student, String> map = new TreeMap<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
//                return 0;
                int i=o1.getAge()-o2.getAge();
//        判断姓名是否一致
                int i2=i==0?o1.getName().compareTo(o2.getName()):i;
                return i2;
            }
        });
//        创建学生对象
        Student s1 = new Student("赵云", 18);
        Student s2 = new Student("马超", 17);
        Student s3 = new Student("黄忠", 21);
        Student s4 = new Student("关羽", 19);
        Student s5 = new Student("赵云", 18);
//       添加元素
        map.put(s1,"厉害");
        map.put(s2,"强大");
        map.put(s3,"忠心");
        map.put(s4,"帅气");
        map.put(s5,"厉害");
//        遍历集合
        Set<Map.Entry<Student, String>> entries = map.entrySet();
        for (Map.Entry<Student, String> keyvalue : entries){
            Student key = keyvalue.getKey();
            String value = keyvalue.getValue();
            System.out.println(key+":"+value);
        }
    }
}

 输出结果:

(4) LinkedHashMap

 class LinkedHashMap extends HashMap implements Map{}

HashMap的一个子类,哈希表和链表实现的Map接口,具有可预测的迭代顺序

哈希表保证元素的唯一,保证键的唯一,链表保证是有序的(存储和取出的顺序一致)

代码举例:

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
 
public class Demo6 {
    public static void main(String[] args) {
        LinkedHashMap<String, String> map = new LinkedHashMap<>();
//        添加元素到集合
        map.put("beijing","国际");
        map.put("winter","冬季");
        map.put("olympics","奥林匹克");
        map.put("sports","运动会");
        map.put("beijing","北京");
//        遍历集合
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String, String> keyvalue : entries){
            String key = keyvalue.getKey();
            String value = keyvalue.getValue();
            System.out.println(key+":"+value);
        }
    }
}

输出结果:

 

(5) HashMap与HashTable的区别:

1、HashMap与HashTable他们存储的单元都是一个个键值对

2、HashMap中的key和value可以为null值,而HashTable不允许。

3、HashTable是线程安全的,而HashMap是线程不安全的。

3、集合的嵌套遍历

需求:从键盘录入"aababcabcdabcde",获取字符串中每一个字母出现的次数要求结果:a(5)b(4)c(3)d(2)e(1)

代码实现:

import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeMap;
 
/*
    需求:从键盘录入"aababcabcdabcde",获取字符串中每一个字母出现的次数要求结果:a(5)b(4)c(3)d(2)e(1)
 */
public class Demo9 {
    public static void main(String[] args) {
//        String s="aababcabcdabcde";
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入你要统计的字符串:");
        String s = sc.next();
        TreeMap<Character, Integer> map = new TreeMap<>();
 
        char[] chars = s.toCharArray();
 
        for (Character ch:chars){
            Integer i = map.get(ch);
            if(i==null){
                map.put(ch,1);
            }else{
                i++;
                map.put(ch,i);
            }
        }
        StringBuffer sb = new StringBuffer();
        Set<Map.Entry<Character, Integer>> entries = map.entrySet();
        for (Map.Entry<Character, Integer> keyvalue : entries){
            Character key = keyvalue.getKey();
            Integer value = keyvalue.getValue();
            sb.append(key).append("(").append(value).append(")");
        }
        String s1 = sb.toString();
        System.out.println(s1);
    }
}

输出结果:

ArrayList嵌套TreeMap

代码举例:

import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
 
public class Demo8 {
    public static void main(String[] args) {
        ArrayList<TreeMap<String, String>> list = new ArrayList<>();
        TreeMap<String, String> map1 = new TreeMap<>();
//        添加元素
        map1.put("邓超", "孙俪");
        map1.put("张杰", "谢娜");
        map1.put("李承铉", "戚薇");
        map1.put("陈小春", "应采儿");
 
        TreeMap<String, String> map2 = new TreeMap<>();
        map2.put("刘备","孙尚香");
        map2.put("周瑜","小乔");
        map2.put("孙策","大乔");
 
        list.add(map1);
        list.add(map2);
 
//        嵌套遍历
        for (TreeMap<String, String> maps : list){
            Set<Map.Entry<String, String>> entries1 = maps.entrySet();
            for (Map.Entry<String, String> keyvalue : entries1){
                String key = keyvalue.getKey();
                String value = keyvalue.getValue();
                System.out.println(key+":"+value);
            }
        }
    }
}

 输出结果:

二、Collections工具类

针对集合操作的工具类

1、Collections与Collection的区别:

1、Collection是单列集合的顶层接口,有两大子类List/Set

2、Collections是一个针对于集合操作的工具类,可以对集合进行排序,还有查找(二分查找)

2、Collections中的方法

代码举例:

import java.util.ArrayList;
import java.util.Collections;
 
public class CollectionsDemo1 {
    public static void main(String[] args) {
        //创建List集合对象
        ArrayList<Integer> list = new ArrayList<>();
      
        //添加元素
        list.add(10);
        list.add(30);
        list.add(20);
        list.add(70);
        list.add(40);
        list.add(50);
        System.out.println(list);
//        System.out.println(list1);
        
        System.out.println("========================================");
        System.out.println("排序前的集合:"+list);
        //public static <T> void sort(List<T> list)
        Collections.sort(list);
        System.out.println("排序后的集合:"+list);
        System.out.println("========================================");
 
        //排序后的集合:[10, 20, 30, 40, 50, 70]
        //public static <T>  binarySearch(List<?> list,T key):二分查找前提是有序
        //二分查找,如果元素存在,返回该元素对应索引
        System.out.println(Collections.binarySearch(list,70));
        System.out.println(Collections.binarySearch(list,700));
 
        //public static <T> T max(Collection<?> coll):查找最大值
        System.out.println("最大值为:"+Collections.max(list));
 
        //public static void reverse(List<?> list) 反转
        Collections.reverse(list);
        System.out.println("反转后的集合:"+list);
 
        //public static void shuffle(List<?> list):随机置换
        Collections.shuffle(list);
        System.out.println("随机置换后的集合:"+list);
    }
}

 输出结果:

对于Collections中

static <T> List<T> synchronizedList(List<T> list) 返回由指定列表支持的同步(线程安全)列表。

 单独举例:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
 
public class CollectionsDemo1 {
    public static void main(String[] args) {
        //创建List集合对象
        ArrayList<Integer> list = new ArrayList<>();
 
        //将ArrayList转换成线程安全的集合,返回的集合和原本的是一个存储空间
        List<Integer> list1 = Collections.synchronizedList(list);
        System.out.println(list.hashCode());
        System.out.println(list1.hashCode());
        
        //添加元素
        list1.add(10);
        list1.add(30);
        list1.add(20);
        list1.add(70);
        list1.add(40);
        list1.add(50);
        System.out.println(list);
        System.out.println(list1);
 
    }
}

输出结果:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值