Java-Map

        Collection接口实现的集合是每次进行单个对象的保存,与之相对的Map集合支持一组对象(偶对象)的存储,Map集合保存的一组对象对象之间的关系是Key = Value(键-值)的结构,在标准的Java类库中包含了Map的几种基本实现。HashMap,Hashtable,TreeMap,LinkedHashMap,WeakHashMap,ConcurrentHashMap,IdentityHashMap。它们的基本接口都是Map,但是它们的行为特性是各不相同的,本博客主要介绍HashMap,Hashtable,TreeMap,ConcurrentHashMap。        先看一下Map接口本身所具有的方法


1:HashMap

        HashMap实现子类是Map集合中最常使用的子类。它再JDK1.8以前是(数组+链表),JDK1.8之后是(数组+链表+红黑树)(阙值8以后使用红黑树)。

        如下代码示例HashMap的基本操作

        HashMap<Integer,String> hashMap2 = new HashMap<>();
        hashMap2.put(1,"A");
        hashMap2.put(2,"A");
        hashMap2.put(3,"A");
        hashMap2.put(3,"B");
        hashMap2.put(null,null);
        System.out.println(hashMap2);

        HashMap的特点:(1)key值不允许重复,如果重复,则会把对应的value更新。(2)key和value都允许为null,key为空有且只能有一个。

        接下来示例:HashMap使用Iterator迭代输出。

        HashMap<Integer,String> hashMap2 = new HashMap<>();
        hashMap2.put(1,"A");
        hashMap2.put(2,"A");
        hashMap2.put(3,"A");
        hashMap2.put(3,"B");
        hashMap2.put(null,null);
//        System.out.println(hashMap2);
        Set<Map.Entry<Integer, String>> set =  hashMap2.entrySet();//获取Set信息
        Iterator<HashMap.Entry<Integer,String>> iterator = set.iterator();//获取Iterator对象
        while(iterator.hasNext()){//迭代输出
            System.out.println(iterator.next());
        }

        Collection接口的实现子类有iterator()方法可以获取Iterator对象,但是Map接口没有此方法,现在看一下Collection和Map是如何进行数据保存的。


        再Map中有一个方法可以把Map集合转化为Set集合

    public Set<Map.Entry<K,V>> entrySet() {
        Set<Map.Entry<K,V>> es;
        return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
    }

        Set集合就是HashSet,它的里面是含有iterator()方法的。所以进行Iterator输出的时候使用的是间接的方法。

扫描二维码关注公众号,回复: 1443776 查看本文章


        我们使用entrySet()方法把Map集合转化为Set集合,Set集合的父接口是Collection,含有iterator()方法。所以就可以拿到Iterator()对象来进行迭代输出。

        示例:取得HashMap中Key值信息

        Set<Integer> set1 = hashMap2.keySet();
        Iterator<Integer> integer = set1.iterator();
        while(integer.hasNext()){
            System.out.println(integer.next());
        }

        如果Key值是一个自定义的类对象,那么进行Key值查重的时候就需要覆写自定义类中的hashCode()方法与equals()方法。现在我举个例子来演示自定义类作为Key的时候的查重。

import java.util.*;

class Student{
    private String name;
    private Integer age;

    Student(String name, Integer age){
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return this.name+" "+this.age;
    }

    @Override
    public boolean equals(Object obj) {//覆写equals方法
        if(this == obj){
            return true;
        }
        if(obj == null){
            return false;
        }
        if(this.getClass() != obj.getClass()){
            return false;
        }
        Student student = (Student)obj;
        return Objects.equals(this.age,student.age) && Objects.equals(this.name,student.name);
    }

    @Override
    public int hashCode() {//覆写hashCode方法
        return Objects.hash(age,name);
    }

}


public class Main{
    public static void main(String[] args)throws Exception{
        HashMap<Student,String> hashMap1 = new HashMap<>();
        hashMap1.put(new Student("AAA",111),"元素一");
        hashMap1.put(new Student("AAA",111),"元素一");
        hashMap1.put(new Student("CCC",333),"元素一");
        hashMap1.put(new Student("CCC",333),"元素一");
        hashMap1.put(new Student("EEE",555),"元素一");
        System.out.println(hashMap1);
        
    }
}

        我们可以看到,覆写了Object类的equals()方法与hashCode()方法之后,HashCode的输出结果实现了去重。


2:Hashtable:

        Hashtable和HashMap还是有一些不同的:

        1:Hashtable中的Key和Value都不允许为空

        2:Hashtable是JDK1.0就推出了,但是HashMap是JDK1.2推出的

        3:HashMap采用异步操作,线程不安全,而Hashtable采用同步操作,线程安全

        4:Hashtable的性能没有HashMap高

        现在我们观察一下Hashtable的操作

        Hashtable<Integer,String> hashtable = new Hashtable<>();
        hashtable.put(1,"A");
        hashtable.put(1,"B");
        hashtable.put(2,"C");
        hashtable.put(2,"D");
        hashtable.put(3,"E");
        System.out.println(hashtable);

        基本上的操作和HashMap类似,进行自定义类的Key输出的时候也是覆写hashCode()方法和equals()方法。


3:ConcurrentHashMap:

       ConcurrentHashMap = Hashtable安全性 + HashMap高性能,既可以保证多个线程查询数据的同步,也可以保持很高效的查询速度,在ConcurrentHashMap中,不允许Key为null

       ConcurrentHashMap的高性能体现在它可以进行数据的分区操作,相比于Hashtable,它采用的不是同步方法而是更加精确的同步锁,所以在进行数据更新的时候只锁对应的区域,而其他区域的访问不受影响。

        ConcurrentHashMap在锁的区域使用了读写锁(读操作异步,写操作同步),可以实现数据更高效的进行访问以及提取。

        ConcurrentHashMap实现数据分桶的原理:


        ConcurrentHashMap在进行数据更新的时候,只会锁住更新的区域,而其他区域的更新与访问不会受到影响。

4:TreeMap:

        TreeMap是一个可以用来排序的子类,它是按照key值来排序的。

        既然是用来排序,那么就会有一个问题,如果使用的是自定义的类对象,那么这个序应该怎么排呢?

        其实实现方法和TreeSet的排序一样,只需要实现Comparable接口中的compareTo()方法就可以了。这里要注意的是:只要自定义类实现了Comparable接口,进行数据的重复判断就不依靠Object类的hashCode()方法和equals()方法了,排序的话,需要我们覆写compareTo()方法。

        示例:使用自定义类对象的Key并且覆写compareTo()方法。

class Children implements Comparable<Children>{
    private Integer grade;
    private Integer classroom;


    Children(Integer grade, Integer classroom){
        this.grade = grade;
        this.classroom = classroom;
    }

    @Override
    public String toString() {
        return "年级"+this.grade+" "+"班级"+this.classroom;
    }

    @Override
    public int compareTo(Children o) {//覆写compareTo接口
        if(this.grade > o.grade){
            return 1;
        }else if(this.grade < o.grade){
            return -1;
        }else {
            return this.classroom.compareTo(o.classroom);
        }
    }
}


public class Main{
    public static void main(String[] args)throws Exception{
        TreeMap<Children,String> treeMap = new TreeMap<>();
        treeMap.put(new Children(6,1),"AAA");
        treeMap.put(new Children(5,1),"AAA");
        treeMap.put(new Children(4,1),"AAA");
        treeMap.put(new Children(3,1),"AAA");
        treeMap.put(new Children(3,1),"AAA");
        treeMap.put(new Children(2,1),"AAA");
        treeMap.put(new Children(2,1),"AAA");
        System.out.println(treeMap);
    }
}

        现在TreeMap不仅实现了去重的功能,而且进行了对自定义类对象的Key与String的Value进行了升序排序。


        有关Map的四个实现子类的基本概念就先总结到这里,希望能对大家有所帮助。

猜你喜欢

转载自blog.csdn.net/qq_38449518/article/details/80410234