双列集合

每次添加一次性添加两个元素。是不可重复的,值是可以重复的,键和值一一对应。一个键和值组合在一起称为键值对(也叫键值对对象,Entry对象)。

Map集合

map集合是双列结合的顶层接口.存取是无序的

Map集合常见API

put(),remove(),clear(),containsKey(),containsValue(),isEmpty().size().

package com.mymap1;

import java.util.HashMap;
import java.util.Map;

public class MyMapDemo1 {
    public static void main(String[] args) {

        Map<String,String> map = new HashMap<>();

        //添加元素
        //put方法可以添加元素,并且可以实现覆盖功能
        //添加数据时键不存在,直接把键值对对象添加到集合
        //添加数据时键存在,会把键值对对象覆盖,并返回被覆盖的值。
        map.put("111","222");
        map.put("333","444");
        map.put("555","666");
        System.out.println(map);
        System.out.println("-------------");

        //remove仅通过key删除时,会返回删除键的值
        //通过键值删除时会返回布尔类型,表示删除成功或失败
        String remove = map.remove("111");
        System.out.println(remove);
//        System.out.println(map.remove("111","222"));
        System.out.println(map);
        System.out.println("-------------");

        //clear()方法
//        map.clear();
//        System.out.println(map);



    }
}

除了put方法,其余方法都是简单可使用的。

Map集合遍历方式

1.键找值

将双列结合的键全部获取出来,组成一个单列结合,然后用遍历单列结合的方式,用get方法获得值。

package com.mymap1;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;

public class MyMapDemo2 {
    public static void main(String[] args) {

        Map<String,String> map = new HashMap<>();

        map.put("aaa","111");
        map.put("bbb","222");
        map.put("ccc","333");

        //利用键找值方式遍历
        Set<String> keys = map.keySet();//调用keySet()方法,将key存入到Set集合中

        //用迭代器也可以
        Iterator<String> iterator = keys.iterator();

        while(iterator.hasNext()){
            String next = iterator.next();
            String s = map.get(next);
            System.out.println(next + "=" + s);
        }
        System.out.println("-------------");
        //增强for遍历单列集合
        for (String key : keys) {
            //System.out.println(key);
            String s = map.get(key);
            System.out.println(key + "=" + s);
        }
        System.out.println("-------------");
        //使用匿名内部类及lambda表达式
//        keys.forEach(new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                String s1 = map.get(s);
//                System.out.println(s + "=" + s1);
//            }
//        });

        keys.forEach(s->{
                String s1 = map.get(s);
                System.out.println(s + "=" + s1);
        });


    }
}

2.键值对

依次获取每一个键值对对象。

package com.mymap1;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;

public class MyMapDemo3 {
    public static void main(String[] args) {
        Map<String,String> map = new HashMap<>();

        map.put("aaa","111");
        map.put("bbb","222");
        map.put("ccc","333");

        //使用键值对对象遍历
        //使用entrySet方法获得所有键值对对象,放入set集合中。
        Set<Map.Entry<String, String>> entries = map.entrySet();

        //迭代器
        Iterator<Map.Entry<String, String>> iterator = entries.iterator();
        while (iterator.hasNext()){
            Map.Entry<String, String> next = iterator.next();
            String key = next.getKey();
            String value = next.getValue();
            System.out.println(key + "=" + value);
        }


        System.out.println("-----------------");
        //增强for
        for (Map.Entry<String, String> entry : entries) {
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + "=" + value);
        }

        System.out.println("-----------------");
        //匿名内部类
        entries.forEach(new Consumer<Map.Entry<String, String>>() {
            @Override
            public void accept(Map.Entry<String, String> s) {
                String key = s.getKey();
                String value = s.getValue();
                System.out.println(key + "=" + value);
            }
        });
        System.out.println("-----------------");
        //lambda表达式
        entries.forEach(s->{
                String key = s.getKey();
                String value = s.getValue();
                System.out.println(key + "=" + value);
        });

    }
}

3.lambda表达式

使用forEach(new biConsumer).

package com.mymap1;

import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;

public class MyMapDemo4 {
    public static void main(String[] args) {

        Map<String,String> map = new HashMap<>();

        map.put("aaa","111");
        map.put("bbb","222");
        map.put("ccc","333");

        map.forEach(new BiConsumer<String, String>() {
            @Override
            public void accept(String key, String value) {
                System.out.println(key + "=" + value);
            }
        });
        System.out.println("--------------------");

        map.forEach(( key,  value)-> System.out.println(key + "=" + value));

    }
}

HashMap

无序、不重复、无索引

也是哈希表结构,与昨天学的HashSet一样,使用hahcode方法和equals方法保证数据不重复。

因为此处存入的是entry对象,但是比较时只计算键的哈希值,因此当键存储的是自定义对象时需要重写hasCode和entry方法。值存储自定义对象却不需要重写。

LinkedHashMap

有序,不重复,无索引。使用双链表实现了存取的有序。

TreeMap

可排序,不重复,无索引。使用键进行排序,默认从小到大。可以自己制定排序规则。

HashMap底层原理

底层会生成一个数组table,数组真正形成是在添加数据时。使用空参构造生成集合时只赋值了加载因子(也就是当数组长度达到数组长度*加载因子个数时,数字自动扩容为原先两倍)。看了源码。

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

TreeMap

    
//添加数据
        private V put(K key, V value, boolean replaceOld) {
        Entry<K,V> t = root;
        if (t == null) {
            addEntryToEmptyMap(key, value);
            return null;
        }
        int cmp;
        Entry<K,V> parent;
        // split comparator and comparable paths
        Comparator<? super K> cpr = comparator;
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else {
                    V oldValue = t.value;
                    if (replaceOld || oldValue == null) {
                        t.value = value;
                    }
                    return oldValue;
                }
            } while (t != null);
        } else {
            Objects.requireNonNull(key);
            @SuppressWarnings("unchecked")
            Comparable<? super K> k = (Comparable<? super K>) key;
            do {
                parent = t;
                cmp = k.compareTo(t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else {
                    V oldValue = t.value;
                    if (replaceOld || oldValue == null) {
                        t.value = value;
                    }
                    return oldValue;
                }
            } while (t != null);
        }
        addEntry(key, value, parent, cmp < 0);
        return null;
    }


    private void addEntry(K key, V value, Entry<K, V> parent, boolean addToLeft) {
        Entry<K,V> e = new Entry<>(key, value, parent);
        if (addToLeft)
            parent.left = e;
        else
            parent.right = e;
        fixAfterInsertion(e);
        size++;
        modCount++;
    }



//红黑规则
        private void fixAfterInsertion(Entry<K,V> x) {
        x.color = RED;

        while (x != null && x != root && x.parent.color == RED) {
            if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
                Entry<K,V> y = rightOf(parentOf(parentOf(x)));
                if (colorOf(y) == RED) {
                    setColor(parentOf(x), BLACK);
                    setColor(y, BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    x = parentOf(parentOf(x));
                } else {
                    if (x == rightOf(parentOf(x))) {
                        x = parentOf(x);
                        rotateLeft(x);
                    }
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateRight(parentOf(parentOf(x)));
                }
            } else {
                Entry<K,V> y = leftOf(parentOf(parentOf(x)));
                if (colorOf(y) == RED) {
                    setColor(parentOf(x), BLACK);
                    setColor(y, BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    x = parentOf(parentOf(x));
                } else {
                    if (x == leftOf(parentOf(x))) {
                        x = parentOf(x);
                        rotateRight(x);
                    }
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateLeft(parentOf(parentOf(x)));
                }
            }
        }
        root.color = BLACK;
    }


注;

HashMap                   默认情况下用这个,因为他的效率最高

LinkedHashMap        需要存取有序时使用

TreeMap                    需要排序时使用。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐