0
点赞
收藏
分享

微信扫一扫

Java基础知识Map集合与Collections工具类

天使魔鬼 2022-03-23 阅读 46
java

Map


Map : 无序的,去重的
        键值对数据的集合
        键值对->映射关系
        价值对: K-V
        K键 : 无序的,去重的|唯一的 ---> Set
        V值 : 无序的,可重复 ---> Collection
        K-V可以为任意引用数据类型

    特点:
        一个key只能对应一个Value
        key相同value覆盖

    遍历方式:
        1.values 获取所有键值对的值
            Collection<V> values() 返回此映射中包含的值的Collection视图。
        2.keySet 获取所有键值对的key,根据key获取value
            Set<K> keySet() 返回此映射中包含的键的Set视图。
        3.entrySet 获取所有的键值对,每一个键值对都是一个Entry类型->表示一个键值对
            Set<Map.Entry<K,V>> entrySet() 返回此映射中包含的映射的Set视图。

TreeMap

import java.util.*;

/*
    TreeMap :
        底层: 红黑树
        存储键值对类型的数据,自动升序排序,去重的
        去重,排序: 根据键值对的key实现,与value本身无关
        TreeSet底层是由TreeMap
        请注意,此实现不同步。

        测试: 使用TreeMap存储键值对数据,key要求为javabean类型教师数据,value存储教授学科,测试存储练习
            是否可以根据key实现去重
            测试是否为升序排序,要求根据教师编号做升序排序

        去重|排序: 根据key的类型的比较规则
                    key的数据类型实现内部比较器
                    传递外部比较规则
 */
public class Class002_TreeMap {
    public static void main(String[] args) {
        //TreeMap<Teacher,String> map = new TreeMap<>(); 根据key的数据类型Teacher默认比较规则
        TreeMap<Teacher,String> map = new TreeMap<>((o1,o2) ->o2.getNo()-o1.getNo()); //根据参数的比较规则对Key的Teacher做比较
        map.put(new Teacher(101,"老薛","JAVA"),"JAVA");
        map.put(new Teacher(103,"宝玉","JAVA"),"JAVA");
        map.put(new Teacher(104,"李老师","JAVA"),"JAVA");
        map.put(new Teacher(102,"李毅大帝","DB"),"DB");

        System.out.println(map);
    }
}

class Teacher implements Comparable<Teacher>{
    private int no;
    private String name;
    private String subject;

    public Teacher() {
    }

    public Teacher(int no, String name, String subject) {
        this.no = no;
        this.name = name;
        this.subject = subject;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", subject='" + subject + '\'' +
                '}';
    }

    @Override
    public int compareTo(Teacher o) {
        return this.no-o.no;
    }
}





HashMap

 HashMap :
        基于哈希表的Map接口的实现。 此实现提供了所有可选的映射操作,并允许null值和null键。
        HashSet 底层是由HashMap
        底层结构 : 哈希表(数组+链表+红黑树)

    哈希表:
          数组 : 节点数组Node[] --> 要求数组的长度为2的整数次幂
            Node : int hash,Object key,Object value,,Node next
          每个索引位置存储的为一个单向链表的首节点(尾插法)
          当链表的长度>8,数组的长度>64,会把链表优化成为红黑树
            当链表的长度>8,但是数组的长度不大于64,这时候会实现扩容(数组的扩容)
    初始容量: 哈希表中的数组默认的初始长度  16
        static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
        数组的容量最大容量 : static final int MAXIMUM_CAPACITY = 1 << 30;
    加载因子: 0.75 一般不建议改变
        默认加载因子 : static final float DEFAULT_LOAD_FACTOR = 0.75f;
    扩容阀值 threshold  : 扩容的临界值  数据的个数size>数组的长度*加载因子 就会扩容
    扩容机制: 原容量的2倍 int newCap = oldCap << 1

    新增功能: 无

    HashMap的哈希表存储数据的过程:
        1.根据key计算哈希值
            通过key的hashCode方法的返回值进一步进行hash算法的运算,得到的整数
            int hash = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);

        2.调用putVal方法实现添加数据(hash,key,value)
            1)判断是否是第一次调用put方法做添加 if ((tab = table) == null || (n = tab.length) == 0)
              如果是第一次添加,直接调用resize()实现扩容
            2)计算位桶的索引 int index = (n - 1) & hash
            3)判断哈希表结构的数组table[index]是否存在数据,
                如果不存在数据,证明没有头节点,创建新节点,放入当前数组的对应索引位置作为头节点
                table[index] = new Node<>(hash, key, value, next);
                size数据的个数+1,判断是否>扩容的阀值,如果大于需要调用resize方法进行扩容,如果不大于,不需要扩容直接返回null
                if (++size > threshold) resize();
                return null;
    如果存在数据,作为链表的头结点,遍历这个链表,拿到每一个节点的key与hash值判断是否与要添加的key和hash相同,如果相同,value覆盖
                    if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
                    value覆盖之后,返回被覆盖的value
                    V oldValue = e.value;
                    e.value = value;
                    return oldValue;
    去重 : 根据key做去重,要求key的数据类型重写hashCode与equals方法

HashMap和HashTable的区别

Hashtable 与 HashMap之间的区别:
        共同点 : 都是Map接口的实现类,底层结构都是哈希表
        异同点 :
            1.继承体系不同
            2.线程是否安全不同
                HashMap 线程不安全|不同步
                Hashtable 线程安全的|同步的
            3.扩容机制不同
                HashMap扩容机制 : 每次扩容原容量的2倍
                    int newCap = oldCap << 1
                Hashtable扩容机制 : 原容量的2倍+1
                    int newCapacity = (oldCapacity << 1) + 1;
            4.键值对数据null值的要求不同
                HashMap 可以存储null值的key与value
                Hashtable key与value都不为null

            5.计算hash值与位桶索引index的算法不同
                HashMap :
                    int hash = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
                    int index = (n - 1) & hash
               Hashtable :
                    int hash = key.hashCode();
                    int index = (hash & 0x7FFFFFFF) % tab.length;

     如何处理HashMap线程不安全问题:
        1.使用Hashtable
        2.使用Collections工具类中static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) 返回由指定映射支持的同步(线程安全)映射。
        3.juc高级并发编程包 ConcurrentHashMap<K,V>-> 线程安全的哈希表

Collections工具类

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/*
    Collections :
        操作集合的工具类
        静态工厂

        void sort(List) //对List容器内的元素排序,排序的规则是按照升序进行排序。
        void shuffle(List) //对List容器内的元素进行随机排列
        void reverse(List) //对List容器内的元素进行逆续排列
        void fill(List, Object) //用一个特定的对象重写整个List容器
        int binarySearch(List, Object)//对于顺序的List容器,采用折半查找的方法查找特定对象
 */
public class Class001_Collections {
    public static void main(String[] args) {
        List<Integer> list= new ArrayList<>();
        list.add(5);
        list.add(3);
        list.add(1);
        list.add(2);
        list.add(4);

        System.out.println(list);

        // void shuffle(List) //对List容器内的元素进行随机排列
        Collections.shuffle(list);
        System.out.println(list);

        //void reverse(List) //对List容器内的元素进行逆续排列
        Collections.reverse(list);
        System.out.println(list);

        //void sort(List) //对List容器内的元素排序,排序的规则是按照升序进行排序。
        Collections.sort(list);
        System.out.println(list);

        //list集合存储javabean类型数据 : 1)内部比较器  2)static <T> void sort(List<T> list, Comparator<? super T> c) 根据指定比较器引发的顺序对指定列表进行排序。

        //void fill(List, Object) //用一个特定的对象重写整个List容器
        //Collections.fill(list,100);
        System.out.println(list);
        //int binarySearch(List, Object)//对于顺序的List容器,采用折半查找的方法查找特定对象
        System.out.println( Collections.binarySearch(list,5));;
    }
}

举报

相关推荐

0 条评论