Java MAP集合

一、Map

Map:键值对的集合|映射的集合 映射关系 key--value 一个key只能对应一个value

key:唯一的,无序的 Set

value:无序的,可重复的 Collection

!!Map接口下所有的实现去重与无序都是根据键值对的key实现的

Map的常用方法

  Map<Integer,String> map = new HashMap<>();
        //V put(K key, V value)
        //将指定值与此映射中的指定键关联(可选操作)。   key相同value覆盖
        map.put(71,"因为");
        map.put(70,"施哥");
        map.put(69,"Lisa");
        map.put(69,"Lisa");
        map.put(69,"李四");
​
        //void putAll(Map<? extends K,? extends V> m)
        //将所有映射从指定映射复制到此映射(可选操作)。
​
        //boolean containsKey(Object key)
        //如果此映射包含指定键的映射,则返回true 。
        System.out.println(map.containsKey(69));
        System.out.println(map.containsValue("Lisa"));
        //boolean containsValue(Object value)
        //如果此映射将一个或多个键映射到指定值,则返回true 。
​
        //void clear()
        //从此映射中删除所有映射(可选操作)。
​
        System.out.println(map);
​
        //static <K, V> Map<K,V> of(K k1, V v1, K k2, V v2)
        //返回包含两个映射的不可修改映射。
        Map<String,Integer> map2 = Map.of("zhangsan",18,"lisi",17);
        System.out.println(map2);
        //map2.put("",10);  //java.lang.UnsupportedOperationException
​
        //V remove(Object key)
        //如果存在,则从此映射中删除键的映射(可选操作)。
        System.out.println(map.remove(70));
        System.out.println("map = " + map);
​
        //default V replace(K key, V value)
        //仅当当前映射到某个值时才替换指定键的条目。
        //default boolean replace(K key, V oldValue, V newValue)
        //仅当当前映射到指定值时才替换指定键的条目。
        System.out.println(map.replace(71,"施哥"));
        System.out.println(map);
​
        //V get(Object key)
        //返回指定键映射到的值,如果此映射不包含该键的映射,则返回null 。
        //int size()
        //返回此映射中键值映射的数量。
        System.out.println(map.size());

Map的遍历:value keySet entrySet

//遍历方式
        //Collection<V> values()   获取所有的value返回
        Collection<String> values = map.values();
        for(String s:values){
            System.out.println(s);
        }
​
        //Set<K> keySet() 返回此映射中包含的键的Set视图。
        Set<Integer> keys = map.keySet();
        for(int i:keys){
            System.out.println(i+"-->"+map.get(i));
        }
​
        //Set<Map.Entry<K,V>> entrySet() 返回此地图中包含的映射的Set视图。
        Set<Map.Entry<Integer,String>> entrys = map.entrySet();
        for(Map.Entry<Integer,String> entry:entrys){
            System.out.println(entry.getKey()+"--->"+entry.getValue());
        }

二、TreeMap

底层:红黑树 TreeSet的底层是TreeMap维护的

特点:可以根据键值对做升序排序

去重与排序:都是根据键值key实现,关注key的比较器

新增方法:新增了一些比较大小相关的方法

遍历方式 : values keySet entrySet

public class TreeMap001 {
    public static void main(String[] args) {
        //TreeMap() --> key的内部比较器
        //使用其键的自然顺序构造一个新的空树映射。
        TreeMap<Double,String> treeMap001=new TreeMap<>();
        treeMap001.put(2344.3,"abs");
        treeMap001.put(23233.3,"ab");
        treeMap001.put(1927.3,"a");
        treeMap001.put(2344.3,"wer");
        System.out.println(treeMap001);
        //TreeMap(Comparator<? super K> comparator)  -->key的外部比较器
        //构造一个新的空树映射,根据给定的比较器排序。
        TreeMap<Student2,String> maps=new TreeMap<>((x,y)->x.getName().compareTo(y.getName()));
        maps.put(new Student2("zhangsan",18),"厦门大学");
        maps.put(new Student2("wangwu",19),"浙江大学");
        maps.put(new Student2("李四",21),"集美大学");
        maps.put(new Student2("zhangsan",18),"武汉大学");
        maps.put(new Student2("zhangsan",19),"南开大学");
        System.out.println(maps);
        //Map.Entry<K,V> ceilingEntry(K key)
        //返回与大于或等于给定键的最小键关联的键值映射,如果没有这样的键,则null 。
        //K ceilingKey(K key)
        //返回大于或等于给定键的最小键,如果没有这样的键,则null 。
        System.out.println(maps.ceilingKey(new Student2("wangwu",19)));
        System.out.println(maps.floorEntry(new Student2("wangliu",19)));
        //Map.Entry<K,V> firstEntry()
        //返回与此映射中的最小键关联的键值映射,如果映射为空,则null 。
        //K firstKey()
        //返回此映射中当前的第一个(最低)键。
        //Map.Entry<K,V> lastEntry()
        //返回与此映射中最大键关联的键值映射,如果映射为空,则null 。
        //K lastKey()
        //返回此映射中当前的最后一个(最高)键。
        System.out.println(treeMap001.firstEntry());
        System.out.println(treeMap001.firstKey());
        //Map.Entry<K,V> higherEntry(K key)
        //返回与严格大于给定键的最小键关联的键值映射,如果没有这样的键,则null 。
        //K higherKey(K key)
        //返回严格大于给定键的最小键,如果没有这样的键,则返回null 。
        //Map.Entry<K,V> lowerEntry(K key)
        //返回与严格小于给定键的最大键关联的键值映射,如果没有这样的键,则null 。
        //K lowerKey(K key)
        //返回严格小于给定键的最大键,如果没有这样的键,则返回null 。
        System.out.println(treeMap001.higherKey(4000.0));
        System.out.println(treeMap001.lowerEntry(4000.0));
        //Map.Entry<K,V> pollFirstEntry()
        //删除并返回与此映射中最小键关联的键值映射,如果映射为空,则null 。
        //Map.Entry<K,V> pollLastEntry()
        //删除并返回与此映射中最大键关联的键值映射,如果映射为空,则null 。
        System.out.println(treeMap001.pollFirstEntry());
        System.out.println(treeMap001.pollLastEntry());
​
​
    }
}
class Student2 {
    private String name;
    private Integer age;
​
    public Student2() {
    }
​
    public Student2(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public Integer getAge() {
        return age;
    }
​
    public void setAge(Integer age) {
        this.age = age;
    }
​
    @Override
    public String toString() {
        return "Student2{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

三、HashMap

HashMap:Map接口的基于哈希表的实现 此实现提供所有可选的映射操作 允许null值和null值

底层逻辑:哈希表

jdk1.7及之前:数组+链表

jdk1.8及之后:数组+链表+红黑树

当单向链表节点个数>8,要求节点数组长度>64,会将单向链表变成红黑树

初始容量(底层数组容量):默认16|可以通过构造器指定

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;

加载因子(计算扩容阈值)loadFactor:默认0.75|可以通过构造器指定

static final float DEFAULT_LOAD_FACTOR = 0.75f;

阈值(扩容临界值)threshold:capacity*loadFactor

扩容机制(底层数组扩容机制):每次扩容原容量2倍

newCap = oldCap << 1

数组的长度为2的整数次幂 此实现不同步

没有新增方法

 HashMap存储过程 :
            1.对要存储的键值对的key调用hash方法,返回key的hash值
                int hash = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
            2.调用putVal方法,同时传递key的hash值,key,value,在方法内部实现添加键值对数据
            3.执行putVal方法
                1)判断哈希表底层节点数组是否为null|是否长度为0 ? 如果是直接调用resize方法实现扩容
                    if ((tab = table) == null || (n = tab.length) == 0)
                        n = (tab = resize()).length;
                2)根据key的hash值与数组长度计算位桶索引
                    int index = (n - 1) & hash;
                3)判断节点数组[index] 是否存在数据,如果不存在,直接创建新节点放入节点数组[index]位置,作为单向链表首节点
                    if ((p = tab[i = (n - 1) & hash]) == null)
                        tab[i] = newNode(hash, key, value, null);
                4)如果存在首节点,p
                    a) : 判断首节点p是否为key相同的节点,如果是key相同的节点,记录它e
                        if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))
                            e = p;
                    b) : 判断首节点p是否为红黑树中的节点,如果是调用putTreeVal方法实现添加,如果不是继续向下判断
                    c) : 顺着单向链表首节点p遍历整个链表,直到找到key相同的节点e或者遍历到原链表的最后创建新节点挂上去结束
                        找到key相同的节点 :
                            if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))
                                break;
                        遍历到原链表的最后创建新节点挂上去 :
                            if ((e = p.next) == null)
                                p.next = newNode(hash, key, value, null);
                5)判断是否存在key相同的节点,如果存在覆盖,返回原value值,方法结束
                    if (e != null) {
                         V oldValue = e.value;
                         e.value = value;
                         return oldValue;
                 6)如果不存在key相同的节点,肯定在之前创建新节点放入到了哈希表中,长度+1,判断是否需要扩容,最后返回null
                    if (++size > threshold)
                        resize();
                        return null;

四、HashTable

HashTable与HashMap的区别:

相同点:都是Map接口的实现类,都存储键值对数据

底层结构都是哈希表,特点相同

不同点:1.继承关系

                                HashMap继承自java.util.AbstractMap<K,V>

                                HashTable继承自java.util.Dictionary<K,V>

              2.对null处理不同

                                HashMap 允许null值和null键

                                HashTable 任何非null对象都可以作用键或值

              3、同步问题

                                HashMap 线程不安全|不同步的

                                HashTable 线程安全|同步的

             4、计算hash值与位桶索引的方式不同

                                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;

             5、初始容量与扩容机制不同

                                HashMap:

                                初始容量:16|可以通过构造器指定

                                扩容机制:每次扩容原来的2倍 newCap = oldCap << 1

                                HashTable:

                                初始容量:11|可以通过构造器指定

                                扩容机制:每次扩容原容量2倍+1 int newCapacity = (oldCapacity << 1) + 1;

如何处理HashMap线程不安全问题 :

1.Hashtable

2.Collections-->static <K, V> Map<K,V> synchronizedMap(Map<K,V> m) 返回由指定映射支持的同步(线程安全)映射。

3.juc-->ConcurrentHashMap ==> 推荐

五、properties

Properties : Properties类表示一组持久的属性。 Properties可以保存到流中或从流中加载。 属性列表中的每个键及其对应的值都是一个字符串。

一般使用Properties的作用都是从配置文件中加载键值对数据

public class Class001_Properties {
    public static void main(String[] args) throws IOException {
        Properties pro = new Properties();
        pro.setProperty("username","zhangsan");
        pro.setProperty("password","1234");
​
        //void store(OutputStream out, String comments)
        //将此Properties表中的属性列表(键和元素对)以适合使用load(InputStream)方法加载到Properties表的格式写入输出流。
        OutputStream os = new BufferedOutputStream(new FileOutputStream("src/dest.properties"));
        pro.store(os,"hahahehe");
        os.flush();
        os.close();
​
        System.out.println(pro.getProperty("username"));
​
        //从流中加载 | 从配置文件中加载键值对数据
        //void load(InputStream inStream)
        //从输入字节流中读取属性列表(键和元素对)。
        pro.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
        System.out.println(pro.getProperty("driver"));
        System.out.println(pro.getProperty("username"));
        System.out.println(pro.getProperty("password"));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值