Java基础——集合体系Map详解

作者 : 开心源码 本文共9192个字,预计阅读时间需要23分钟 发布时间: 2022-05-12 共127人阅读

Java基础——集合体系Map详解

上文中我们理解了集合体系中的单列集合:Java基础——集合以及Java集合——Set详解,接下来呢就让阿Q带大家一起学习一下双列集合map的使用吧。

集合体系

单列集合顶层接口 遍历方式:加强for,Iterator,集合转数组Collection    |-List 存取有序,元素可以重复,有序就有索引,有索引即可以通过索引操作元素。遍历方式:普通for,加强for,Iterator,ListIterator,集合转数组        |-ArrayList 不安全,效率高,数组结构:增删慢;查询快        |-LinkedList不安全,效率高,链表结构:增删快;查询慢        |-Vector    数组结构 安全 效率低    |-Set 存取无序,元素唯一。遍历方式:加强for,Iterator,集合转数组        |-HashSet    哈希算法 哈希结构 存取无序 元素唯一            |-LinkedHashSet        |-TreeSet   二叉树算法可以排序双列集合Map双列集合,键唯一,值可以重复,遍历方式:根据键找值,根据键值对找键和值    |-HashMap底层的哈希结构 保证键的唯一        |-LinkedHashMap:存入和取出的顺序相同,同时键也是通过哈希算法保证元素唯一性的    |-TreeMap底层的二叉树结构 保证键的排序和唯一

Map:双列集合

特点:Map双列集合,Collection是单列集合;键不可以重复,值可以重复;数据结构针对键有效。

方法:

  • 增加功能:V put(K key,V value):增加元素,假如键是第一次存储,就直接存储元素,返回null;假如键不是第一次存在,就用值把以前的值替换掉,返回以前的值。
  • 删除功能:void clear():移除所有的键值对元素;V remove(Object key):根据键删除键值对元素,并把值返回。
  • 判断功能:boolean containsKey(Object key):判断集合能否包含指定的键;boolean containsValue(Object value):判断集合能否包含指定的值;boolean isEmpty():判断集合能否为空
  • 获取功能:Set<Map.Entry<K,V>> entrySet():获取所有的键值对的集合;V get(Object key):根据键获取值;Set<K> keySet():获取集合中所有键的集合;Collection<V> values():获取集合中所有值的集合
  • 长度功能:int size():返回集合中的键值对的个数

代码演示:

public static void demo1() {    Map<String, Integer> map = new HashMap<>();    Integer i1 = map.put("张三", 23); //假如键是第一次存储,就直接存储元素,返回null    Integer i2= map.put("李四", 24);    Integer i3 = map.put("王五", 25);    Integer i4 = map.put("赵六", 26);    Integer i5 = map.put("张三", 26); //相同的键不存储,值覆盖,把被覆盖的值返回    System.out.println(map);        //{赵六=26, 张三=26, 李四=24, 王五=25}    System.out.println(i1);         //null    System.out.println(i2);         //null    System.out.println(i3);         //null    System.out.println(i4);         //null    System.out.println(i5);         //23假如键不是第一次存在,就用值把以前的值替换掉,返回以前的值}public static void demo2() {    Map<String, Integer> map = new HashMap<>();    map.put("张三", 23);    map.put("李四", 24);    map.put("王五", 25);    map.put("赵六", 26);    Integer value = map.remove("张三");   //根据键删除元素,返回键对应的值    System.out.println(value);          //23    System.out.println(map.containsKey("张三"));      //false 判断能否包含传入的键    System.out.println(map.containsValue(100));     //false 判断能否包含传入的值                System.out.println(map);                //{赵六=26, 李四=24, 王五=25}}public static void main(String[] args) {    Map<String, Integer> map = new HashMap<>();    map.put("张三", 23);    map.put("李四", 24);    map.put("王五", 25);    map.put("赵六", 26);    Collection<Integer> c = map.values();           //获取集合中所有值的集合    System.out.println(c);                  //[26, 23, 24, 25]    System.out.println(map.size());             //4}

遍历
方式一:通过keySet()获取所有键的集合,而后遍历键的集合,获取到每一个键,而后通过getKey()方法获取每一个值,这样把键和值逐个对应的找出来了,就遍历了集合。需要用到的方法:V get(Object key):根据键获取值,
Set<K> keySet():获取集合中所有键的集合。

代码演示:

public static void main(String[] args) {    Map<String, Integer> map = new HashMap<>();    map.put("张三", 23);    map.put("李四", 24);    map.put("王五", 25);    map.put("赵六", 26);    //获取所有的键    /*    Set<String> keySet = map.keySet();      //获取所有键的集合    Iterator<String> it = keySet.iterator();    //获取迭代器    while(it.hasNext()) {               //判断集合中能否有元素        String key = it.next();         //获取每一个键        Integer value = map.get(key);       //根据键获取值        System.out.println(key + "=" + value);    }    */    //使用加强for循环遍历    for(String key : map.keySet()) {        //map.keySet()是所有键的集合        System.out.println(key + "=" + map.get(key));    }}

方式二:通过entrySet()获取所有的键值对的集合,而后遍历键值对的集合,获取每一个键值对,而后根据键值对来获取每一个键和值,这样把键和值逐个对应的找出来了,就遍历了集合。需要用到的方法:Set<Map.Entry<K,V>> entrySet():获取所有的键值对的集合,Map.Entry接口里面的K getKey():获取键值对中的键,V getValue():获取键值对中的值。

代码演示:

public static void main(String[] args) {    Map<String, Integer> map = new HashMap<>();    map.put("张三", 23);    map.put("李四", 24);    map.put("王五", 25);    map.put("赵六", 26);    //Map.Entry说明Entry是Map的内部接口,将键和值的键值对封装成了Entry对象,并存储在Set集合中    /*    Set<Map.Entry<String, Integer>> entrySet = map.entrySet();    //获取每一个 键值对 对象    Iterator<Map.Entry<String, Integer>> it = entrySet.iterator();    while(it.hasNext()) {        //获取每一个键值对对象        Map.Entry<String, Integer> en = it.next();  //父类引用指向子类对象        //Entry<String, Integer> en = it.next();    //直接获取的是子类对象        String key = en.getKey();           //根据键值对对象获取键        Integer value = en.getValue();          //根据键值对对象获取值        System.out.println(key + "=" + value);    }    */    for(Entry<String, Integer> en : map.entrySet()) {        System.out.println(en.getKey() + "=" + en.getValue());    }}

Map.Entry原理:Entry是Map接口里面的一个内部接口, 他的实现类是Map子类里面的一个静态的内部类

HashMap

键是如何保证唯一性的呢? 通过哈希算法。 HashSet底层就是通过HashMap的键来完成的,所以说HashMap保证键的唯一性必需要让键的元素所在的类去重写 hashCode()和 equals()方法。

代码演示:

public static void main(String[] args) {    HashMap<Student, String> hm = new HashMap<>();    //Student作为键,必需重写equals和hashCode() 才能让HashMap保证键的唯一    hm.put(new Student("张三", 23), "北京");        hm.put(new Student("张三", 23), "上海");    hm.put(new Student("李四", 24), "广州");    hm.put(new Student("王五", 25), "深圳");        System.out.println(hm); //{Student [name=张三, age=23]=上海, Student [name=李四, age=24]=广州, Student [name=王五, age=25]=深圳}  去掉了重复的 "张三", 23}   public class Student{       //重写了equals和HashCode的 Student类    private String name;    private int age;    public Student() {        super();                }    public Student(String name, int age) {        super();        this.name = name;        this.age = age;    }    @Override    public String toString() {        return "Student [name=" + name + ", age=" + age + "]";    }    @Override    public int hashCode() {             //重写hashCode方法        final int prime = 31;        int result = 1;        result = prime * result + age;        result = prime * result + ((name == null) ? 0 : name.hashCode());        return result;    }    @Override    public boolean equals(Object obj) {     //重写equals方法        if (this == obj)            return true;        if (obj == null)            return false;        if (getClass() != obj.getClass())            return false;        Student other = (Student) obj;        if (age != other.age)            return false;        if (name == null) {            if (other.name != null)                return false;        } else if (!name.equals(other.name))            return false;        return true;    }}

LinkedHashMap

存入和取出的顺序相同,同时键也是通过哈希算法保证元素唯一性的。

public static void main(String[] args) {    LinkedHashMap<String, Integer> lhm = new LinkedHashMap<>();    lhm.put("张三", 23);    lhm.put("李四", 24);    lhm.put("赵六", 26);    lhm.put("王五", 25);    System.out.println(lhm);//{张三=23, 李四=24, 赵六=26, 王五=25}  存取有序}

TreeMap

键是如何保证排序和唯一的呢?通过二叉树算法,TreeSet的底层就是通过TreeMap的键来完成的。

方式一:所以TreeMap保证键的唯一和排序需要让 TreeMap的键的元素所在的类去实现自然排序Comparable接口;

方式二:TreeMap保证键的唯一和排序 需要调用TreeMap的有参构造,传入一个比较器 Comparator

代码演示:

    public static void main(String[] args) {        TreeMap<Student, String> tm = new TreeMap<>(new Comparator<Student>() {             //用TreeMap的有参构造方法 传入比较器            @Override            public int compare(Student s1, Student s2) {                int num = s1.getName().compareTo(s2.getName());     //按照姓名比较                return num == 0 ? s1.getAge() - s2.getAge() : num;            }        });        tm.put(new Student("张三", 23), "北京");        tm.put(new Student("李四", 13), "上海");        tm.put(new Student("赵六", 43), "深圳");        tm.put(new Student("王五", 33), "广州");                System.out.println(tm);    }?   public static void demo1() {?       TreeMap<Student, String> tm = new TreeMap<>();  //用TreeMap的无参构造方法创立的对象?       //Student作为键,必需让Student实现Comparable接口 并且重写CompareTo方法        tm.put(new Student("张三", 23), "北京");    ?       tm.put(new Student("李四", 13), "上海");?       tm.put(new Student("王五", 33), "广州");?       tm.put(new Student("赵六", 43), "深圳");?       ?       System.out.println(tm);?   }    //Student实现了Comparable接口 重写了CompareTo方法?   public class Student implements Comparable<Student> {   ?       private String name;?       private int age;?       public Student() {?           super();    ?       }?       public Student(String name, int age) {?           super();?           this.name = name;?           this.age = age;?       }?       ?       @Override?       public int compareTo(Student o) {       // 重写了CompareTo方法?           int num = this.age - o.age;     //以年龄为主要条件?           return num == 0 ? this.name.compareTo(o.name) : num;?       }?   }

HashMap的嵌套

学校一年级学生HashMap    键:一年级对象HashMap   值:班号1        键:学生对象 值:归属地            键:学生对象 值:归属地    键:一年级对象HashMap   值:班号2        键:学生对象 值:归属地        键:学生对象 值:归属地

代码演示:

public static void main(String[] args) {    //定义一年级1班    HashMap<Student, String> hm1 = new HashMap<>();    hm1.put(new Student("张三", 23), "北京");    hm1.put(new Student("李四", 24), "北京");    hm1.put(new Student("王五", 25), "上海");    hm1.put(new Student("赵六", 26), "广州");    //定义一年级2班    HashMap<Student, String> hm2 = new HashMap<>();    hm2.put(new Student("唐僧", 1023), "北京");    hm2.put(new Student("孙悟空",1024), "北京");    hm2.put(new Student("猪八戒",1025), "上海");    hm2.put(new Student("沙和尚",1026), "广州");    //定义双元课堂    HashMap<HashMap<Student, String>, String> hm = new HashMap<>();    hm.put(hm1, "一年级1班");    hm.put(hm2, "一年级2班");    //遍历双列集合    for(HashMap<Student, String> h : hm.keySet()) {             //hm.keySet()代表的是一年级所有的班级集合  h是每个班级        String value = hm.get(h);           //get(h)根据班级对象获取班级代号value        //遍历键的双列集合对象        for(Student key : h.keySet()) { //h.keySet()代表班级中所有的学生对象集合,key是每个学生            String value2 = h.get(key);     // h.get(key) 根据学生对象找到学生的所在地value2            System.out.println(key + "=" + value2 + "=" + value);        }    }}

HashMap和Hashtable

1:HashMap线程不安全,效率高,1.2出现的;Hashtable线程安全的,效率低,1.0出现的。
2:HashMap可以存null键或者null值,Hashtable不可以存储null键或者null值。

代码演示:

public static void main(String[] args) {    HashMap<String, Integer> hm = new HashMap<>();    hm.put(null, 23);       //不报错       hm.put("李四", null);     //不报错    System.out.println(hm);     //{null=23, 李四=null}    /*    Hashtable<String, Integer> ht = new Hashtable<>();    ht.put(null, 23);       //编译不报错,运行报错java.lang.NullPointerException    ht.put("张三", null);     //编译不报错,运行报错java.lang.NullPointerException    System.out.println(ht);         */}

Collections

public static <T extends Comparable<? super T>> void sort(List<T> list);排序:只能给List排序,而且要求被排序的List集合里面存储的元素必需实现Comparable接口(对象只有实现了Comparable接口,才能说明对象具有比较性)

public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key);在已经排好序的list集合中查找key的索引,List集合中的元素必需实现Comparable接口

public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll);给求Collection集合中最大的元素,Collection集合的元素必需实现了Comparable接口,由于假如元素不具有比较性 我如何知道谁最大呢?

public static void reverse(List<?> list);把list集合反转,list集合里面的元素没有任何要求

public static void shuffle(List<?> list);把list集合里面的元素打乱顺序,list集合里面的元素没有任何要求

代码演示:

public static void main(String[] args) {    ArrayList<String> list = new ArrayList<>();    list.add("a");    list.add("c");    list.add("d");    list.add("g");    list.add("f");  //String类实现了Comparable接口重写了CompareTo方法,所以可以求最大值    //根据list集合存的元素里面的CompareTo方法的比较规则 获取集合中的最大值    System.out.println(Collections.max(list));//g    Collections.reverse(list);          //反转集合    Collections.shuffle(list);          //随机置换,可以用来洗牌    System.out.println(list);           //[g, f, d, a, c]}public static void demo() {    ArrayList<String> list = new ArrayList<>();    list.add("a");    list.add("c");    list.add("d");    list.add("f");    list.add("g");    Collections.sort(list); //进行二分法查找之前,必需先把list集合排序        System.out.println(Collections.binarySearch(list, "c"));    //1    System.out.println(Collections.binarySearch(list, "b"));    //-2}

好了集合的一律内容就先总结到这了,以后假如遇到什么问题再继续升级。想理解更多学习知识,请关注微信公众号“阿Q说”,获取更多学习资料吧!你也可以后端留言说出你的疑惑,阿Q将会在后期的文章中为你解答。每天学习一点点,每天进步一点点。

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Java基础——集合体系Map详解

发表回复