Heim  >  Artikel  >  Java  >  So schreiben Sie den Implementierungscode der Java-Sammlung

So schreiben Sie den Implementierungscode der Java-Sammlung

WBOY
WBOYnach vorne
2023-05-05 23:04:051047Durchsuche

1. HashMap

public class HashMapDemo {
    private Map map = null;
    public void init() {
        map = new HashMap();
        map.put("a", "aaa");
        map.put("b", "bbb");
        map.put("c", "ccc");
        System.out.println(map);
    }
    // 添加元素
    public void testPut() {
        // V put(K key, V value) :把指定的key和value添加到集合中
        map.put("a1", "aaa");
        map.put("b1", "bbb");
        map.put("c1", "ccc");
        System.out.println(map);
        // void putAll(Map<? extends K,? extends V>m) :把指定集合添加集合中
        Map map1 = new HashMap();
        map1.put("e", "eee");
        map1.put("f", "fff");
        map.putAll(map1);
        System.out.println(map);
        // default V putIfAbsent(K key, V value) :如果key不存在就添加
        map.putIfAbsent("a", "hello");
        System.out.println(map);
        map.putIfAbsent("g", "ggg");
        System.out.println(map);
    }
    // 修改元素
    public void testModify() {
        // V put(K key, V value) :把集合中指定key的值修改为指定的值
        map.put("a", "hello");
        map.put("a", "world");
        System.out.println(map);
        // 说明,当key相同时,后面的值会覆盖前面的值。
        // default V replace(K key, V value) :根据key来替换值,而不做增加操作
        Object replace = map.replace("b1", "java");
        System.out.println(replace);
        System.out.println(map);
        //default boolean replace(K key, V oldValue,V newValue)
    }
    // 删除元素
    public void testRemove() {
        // V remove(Object key) :根据指定key删除集合中对应的值
        Object c = map.remove("c");
        System.out.println(c);
        System.out.println(map);
        // default boolean remove(Object key, Objectvalue) :根据key和value进行删除
        map.remove("b", "bbb1");
        System.out.println(map);
        // void clear() :清空集合中所有元素
        map.clear();
        System.out.println(map);
    }
    // 判断元素
    public void testJudge() {
        // boolean isEmpty() :判断集合是否为空,如果是返回true,否则返回false
        System.out.println(map.isEmpty());
        // boolean containsKey(Object key) :判断集合中是否包含指定的key,包含返回true,否则返回false
        boolean flag = map.containsKey("a");
        System.out.println(flag); // true
        flag = map.containsKey("a1");
        System.out.println(flag); // false
        // boolean containsValue(Object value) :判断集合中是否包含指定的value,包含返回true,否则返回false
        flag = map.containsValue("aaa");
        System.out.println(flag); // true
        flag = map.containsValue("aaa1");
        System.out.println(flag); // false
    }
    // 获取元素
    public void testGet() {
        // int size() :返回集合的元素个数
        int size = map.size();
        System.out.println(size);
        // V get(Object key) :根据Key获取值,如果找到就返回对应的值,否则返回null
        Object val = map.get("a");
        System.out.println(val);
        val = map.get("a1");
        System.out.println(val); // null
        // default V getOrDefault(Object key, VdefaultValue) :根据Key获取值,如果key不存在,则返回默认值
        val = map.getOrDefault("a1", "hello");
        System.out.println(val);
        // Collection<V> values() :返回集合中所有的Value
        Collection values = map.values();
        for (Object value : values) {
            System.out.println(value);
        }
        // Set<K> keySet() :返回集合中所有的Key
        Set set = map.keySet();
        for (Object o : set) {
            System.out.println(o);
        }
    }
    // 迭代元素
    public void testIterator() {
        // 第一种:通过key获取值的方式
        Set keySet = map.keySet();
        Iterator it = keySet.iterator();
        while (it.hasNext()) {
            Object key = it.next();
            Object val = map.get(key);
            System.out.println(key + "=" + val);
        }
        System.out.println("------------------------ ");
        // 第二种:使用for循环
        for (Object key : map.keySet()) {
            System.out.println(key + "=" +
                               map.get(key));
        }
        System.out.println("------------------------ ");
        // 第三种:使用Map接口中的内部类来完成,在框架中大量使用
        Set entrySet = map.entrySet();
        for (Object obj : entrySet) {
            Map.Entry entry = (Map.Entry) obj;
            System.out.println(entry.getKey() + "=" +
                               entry.getValue());
        }
    }
}

Hinweis: In HashMap darf der Schlüsselwert leer sein, aber der Schlüssel ist eindeutig und der Wert kann wiederholt werden. hashMap ist nicht threadsicher.

2. TreeMap

ist eine geordnete Sammlung, die standardmäßig eine natürliche Sortierung verwendet.

public class Person implements Comparable {
    private String name;
    private int age;
    @Override
    public int compareTo(Object o) {
    if (o instanceof Person) {
    Person p = (Person) o;
    return this.age - p.age;
    }
    return 0;
}
    public Person() {}
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person{" +
            "name='" + name + '\'' +
            ", age=" + age +
            '}';
    }
}

Test

public class TeeMapDemo {
    @Test
    public void testInteger() {
        TreeMap tm = new TreeMap();
        tm.put(3, 333);
        tm.put(2, 222);
        tm.put(11, 111);
        tm.put(2, 222);
        System.out.println(tm);
    }
    @Test
    public void testString() {
        TreeMap tm = new TreeMap();
        tm.put("hello", "hello");
        tm.put("world", "world");
        tm.put("about", "");
        tm.put("abstract", "");
        System.out.println(tm);
    }
    @Test
    public void testPerson() {
        TreeMap tm = new TreeMap(new Comparator(){
            @Override
            public int compare(Object o1, Object o2) {
                if (o1 instanceof Person && o2
                    instanceof Person) {
                    Person p1 = (Person) o1;
                    Person p2 = (Person) o2;
                    return p1.getAge() - p2.getAge();
                }
                return 0;
            }
        });
        tm.put(new Person("张三",18), null);
        tm.put(new Person("李四",17), null);
        System.out.println(tm);
    }
}

Erklärung: Aus dem obigen Code können wir erkennen, dass die Verwendung von TreeMap der Verwendung von TreeSet sehr ähnlich ist. Wenn wir den Quellcode der HashSet-Sammlung betrachten, können wir sehen, dass beim Erstellen einer HashSet-Sammlung HashMap wird tatsächlich unten verwendet.

public HashSet() {
	map = new HashMap<>();
}

HashSet speichert tatsächlich den Schlüssel von HashMap.

3.ConcurrentHashMap

In der Map-Sammlung haben wir HashMap und TreeMap eingeführt. Im Fall von Multithreading sind diese Sammlungen nicht threadsicher, also Threads Es können Sicherheitsprobleme auftreten. HashMapTreeMap,在多线程的情况下这些集合都不是线程安全的,因此可能出现线程安全的问题。

在Java中Hashtable是一种线程安全的HashMapHashtable在方法上与HashMap并无区别,仅仅只是在方法使用了synchronized以此来达到线程安全的目的,我们观察Hashtable的源码。

public synchronized V get(Object key) {
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {
                return (V)e.value;
            }
        }
        return null;
    }

以上是Hashtable的get源码,可以看出它仅仅只是在方法上添加了锁,这大大降低了线程的执行效率,以牺牲效率的形式来达到目的,这显然不是我们在实际中想要的,因此我们需要一种既能在线程安全方面有保障,在效率上还可以的方法。

ConcurrentHashMap采用的是分段锁的原理,我们观察源码。

 public V put(K key, V value) {
        return putVal(key, value, false);
    }
final V putVal(K key, V value, boolean onlyIfAbsent) {
        if (key == null || value == null) throw new NullPointerException();
        int hash = spread(key.hashCode());
        int binCount = 0;
        for (Node<K,V>[] tab = table;;) {
            Node<K,V> f; int n, i, fh;
            if (tab == null || (n = tab.length) == 0)
                tab = initTable();
            else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
                if (casTabAt(tab, i, null,
                             new Node<K,V>(hash, key, value, null)))
                    break;                   // no lock when adding to empty bin
            }
            else if ((fh = f.hash) == MOVED)
                tab = helpTransfer(tab, f);
            else {
                V oldVal = null;
                synchronized (f) {
                    if (tabAt(tab, i) == f) {
                        if (fh >= 0) {
                            binCount = 1;
                            for (Node<K,V> e = f;; ++binCount) {
                                K ek;
                                if (e.hash == hash &&
                                    ((ek = e.key) == key ||
                                     (ek != null && key.equals(ek)))) {
                                    oldVal = e.val;
                                    if (!onlyIfAbsent)
                                        e.val = value;
                                    break;
                                }
                                Node<K,V> pred = e;
                                if ((e = e.next) == null) {
                                    pred.next = new Node<K,V>(hash, key,
                                                              value, null);
                                    break;
                                }
                            }
                        }
                        else if (f instanceof TreeBin) {
                            Node<K,V> p;
                            binCount = 2;
                            if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
                                                           value)) != null) {
                                oldVal = p.val;
                                if (!onlyIfAbsent)
                                    p.val = value;
                            }
                        }
                    }
                }
                if (binCount != 0) {
                    if (binCount >= TREEIFY_THRESHOLD)
                        treeifyBin(tab, i);
                    if (oldVal != null)
                        return oldVal;
                    break;
                }
            }
        }
        addCount(1L, binCount);
        return null;
    }

从源码中可以看出ConcurrentHashMap

In Java ist Hashtable eine threadsichere HashMap. Es gibt keinen Unterschied zwischen Hashtable und HashMap in Bezug auf die Methoden Wird in Methoden verwendet. synchronized wird verwendet, um Thread-Sicherheit zu erreichen. Wir beobachten den Quellcode von Hashtable.

rrreee

Das Obige ist der Get-Quellcode von Hashtable. Es ist ersichtlich, dass er der Methode nur eine Sperre hinzufügt, was die Ausführungseffizienz des Threads erheblich verringert und den Zweck auf Kosten der Effizienz erreicht was wir in der Praxis wollen, also brauchen wir eine Methode, die sowohl threadsicher als auch effizient ist. 🎜🎜ConcurrentHashMap verwendet das Prinzip der segmentierten Sperre. Schauen wir uns den Quellcode an. 🎜rrreee🎜Aus dem Quellcode geht hervor, dass ConcurrentHashMap nur dann eine Sperre hinzufügt, wenn ein Thread die aktuellen Daten verarbeitet, sodass die Effizienz erheblich verbessert wird. 🎜🎜Verbesserte Effizienz bei gleichzeitiger Thread-Sicherheit. 🎜

Das obige ist der detaillierte Inhalt vonSo schreiben Sie den Implementierungscode der Java-Sammlung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen