欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

新手了解java 集合基础知识(二)

程序员文章站 2022-03-08 19:54:51
目录三、map1、hashmap2、treemap3.concurrenthashmap三、map​ 存储的双列元素,key是无序的,不可重复,而value是无序,可重复的。1、hashm...

三、map

​ 存储的双列元素,key是无序的,不可重复,而value是无序,可重复的。

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());
        }
    }
}

说明:在hashmap中键-值允许为空,但键唯一,值可重复。hashmap不是线程安全的。

2、treemap

是一个有序的集合,默认使用的是自然排序方式。

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 +
            '}';
    }
}

测试

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);
    }
}

说明:从上面的代码可以发现,treemap的使用和treeset的使用非常相似,观察hashset集合的源代码可以看出,当创建 hashset集合时,其实是底层使用的是hashmap。

public hashset() {
	map = new hashmap<>();
}

hashset实际上存的是hashmap的key。

3.concurrenthashmap

在map集合中我们介绍了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仅仅是在当有线程去操作当前数据的时候添加了锁,因此效率大大提高了。

在线程安全的情况下提高了效率。

总结

本篇文章就到这里了,希望能对你有所帮助,也希望您能够多多关注的更多内容!