Java基础之集合 List、Map和Set

List介绍

List是Java中比较常用的集合类型之一,它是一个接口,继承于Collection接口,其中实现类中常见的有ArrayList、LinkedList、Vector等子类。
List中元素可以重复,并且是有序的。(这里的有序指的是按照放入的顺序进行存储。)
1、ArrayList底层是数组实现的,是一种可以动态增长和缩减的索引序列。数组和数组列表中有一个重大的缺陷:从数组的中间位置删除一个元素要付出很大的代价,因为在数组中处于被删除元素之后的所有元素都要向数组前端移动,在数组中间插入元素也是如此,所以数组在删除和插入的操作上效率低。
实现:

public void invoke(){
        //初始化
        List list=new ArrayList<>();
        //赋值
        list.add("one");
        list.add("two");
        list.add("one");
        list.add("one");
        list.add("abc");
        Log.d("TestList","size===="+list.size());
         //遍历集合
        for (int i = 0; i < list.size(); i++) {
            String str=list.get(i);
            Log.d("TestList",str);
        }

        Log.d("TestList","------------remove------------");
        //for循环删除元素
        for (int i = 0; i < list.size(); i++) {
            String str=list.get(i);
            if(str.equals("one")){
                list.remove(i);
            }
            Log.d("TestList",str);
        }

    }
TestList: size====5
TestList: [one, two, one, one, abc]
TestList: ----for循环remove----
TestList: [two, one, abc]

通过ArrayList的remove方法进行删除元素打印出的结果中还存在one,出现删除的元素并没有完全被删除的情况。

        Log.d("TestList","----遍历器删除----");
        for (String s : list) {
            if(s.equals("one")){
                list.remove(s);
            }
        }
        Log.d("TestList",list.toString());
   通过遍历器删除,报以下异常
   Caused by: java.util.ConcurrentModificationException
        Log.d("TestList","----Iterator----");
        //迭代器删除元素
        Iterator iterator=list.iterator();
        while (iterator.hasNext()) {
            if(iterator.next().equals("one")){
                iterator.remove();
            }
        }
        Log.d("TestList",list.toString());
TestList: ----Iterator----
TestList: [two, abc]

通过迭代器判断进行删除元素,打印结果正常。
综上所述,在对ArrayList进行遍历删除时,建议使用迭代器Iterator进行遍历删除。(面试中被问到的几率还是不小的)
2、LinkdeList底层是链表实现的。是一种可以在任何位置进行高效的插入和删除的有序序列。链表将每个对象存放在独立的结点中,每个结点还存放着序列中下一个结点的引用。所以在链表中删除一个元素是一个很轻松的操作,只需要对被删除元素附近的结点更新一下即可。在Java程序语言中,所有链表实际上都是双向链接的(doubly linked),每个结点还存放着指向前驱结点的引用。
实现:

 public void invoke(){
        List list=new LinkedList<>();
        list.add("aaa");
        list.add("abc");
        list.add("aa");
        Log.d("Testlinked",list.toString()+",size===="+list.size());
    }
Testlinked: [aaa, abc, aa],size====5
双向链表
        Log.d("Testlinked","-----Iterator-----");
        Iterator iterator=list.iterator();
        String first=iterator.next();
        String second=iterator.next();
        iterator.remove();
        Log.d("Testlinked",list.toString());
Testlinked: -----Iterator-----
Testlinked: [aaa, aa]
从链表中删除一个元素

3、Vector和ArrayList一样底层都是数据实现的,Vector是线程安全的,ArrayList、LinkedList都是线程不安全的,即在多线程下修改数据可能会造成数据错乱,重复增删等问题。Vector中的很多重要方法都是用synchronized实现同步,保证线程安全。在多线程下如果要保证线程安全,那么使用Vector比较好,但是在保证线程安全的同时效率也会下降。如果你的程序不涉及到线程安全问题,那么使用ArrayList是更好的选择(因为Vector使用synchronized,必然会影响效率)。
Vector和ArrayList二者之间还有一个区别,就是扩容策略不一样。在List被第一次创建的时候,会有一个初始大小,随着不断向List中增加元素,当List认为容量不够的时候就会进行扩容。Vector缺省情况下自动增长原来一倍的数组长度,ArrayList增长原来的50%。

综上所述,在需要频繁读取集合中的元素时,使用ArrayList效率较高,而在插入和删除操作较多时,使用LinkedList效率较高。使用Vector可以多线程下保证修改数据线程安全(当然,你也可以使用ArrayList并自己实现同步)。

Set介绍

Set也是ava中比较常用的集合类型之一,它是一个接口,和List一样继承于Collection接口,其中实现类中常见的有HashSet、TreeSet等子类。Set是没有重复元素的集合,是无序的。
1、HashSet实现了基于散列表的集。可以用add方法添加元素。可以快速的查看某个元素是否出现在集中,只在某个桶中查找元素,而不必查看集合中的所有元素。HashSet不能存储重复的值,如果key已存在内容会被覆盖。允许null值,非线程安全。
实现:

public void invoke(){
        Set set=new HashSet<>();
        set.add("abc");
        set.add("ab");
        set.add("ccc");
        Log.d("TestSet",set.toString());
        //存储null值
        set.add(null);
        Log.d("TestSet",set.toString());
        set.add("oi");
        Log.d("TestSet",set.toString());
        //存储相同的值
        set.add("oi");
        Log.d("TestSet",set.toString());
        //遍历
        Iterator iterator=set.iterator();
        while (iterator.hasNext()) {
        String str=iterator.next();
            Log.d("TestSet",str+"");
        }
    }
TestSet: [abc, ab, ccc]
TestSet: [null, abc, ab, ccc]
TestSet: [null, abc, oi, ab, ccc]
TestSet: [null, abc, oi, ab, ccc]

2、TreeSet类与散列集十分相似,不过,它比散列集有所改进。树集是一个有序的集合。可以以任意顺序将元素插入到集合中。在对集合进行遍历时,每个值会自动的按照排序后的顺序呈现。
实现:

 public void invoke(){
        Set set=new TreeSet<>();
        set.add(777);
        set.add(1);
        set.add(23);
        set.add(98);
        set.add(33);
        set.add(66);
        Log.d("TestTree",set.toString());
    }
TestTree: [1, 23, 33, 66, 98, 777]

Map介绍

Map是以键值对形式存储数据,不能存储重复的元素。有HashMap、LinkedHashMap、TreeMap等子类。
1、HashMap是哈希表结构,不保证存取顺序,允许null键或者null值,效率较高。实现了Map接口。

public void invoke(){
        Map map=new HashMap();
        map.put("aaa","aaa");
        Log.d("TestMap",map.toString());
        map.put(null,null);
        Log.d("TestMap",map.toString());

        Log.d("TestMap","aaa==="+map.get("aaa"));
        Log.d("TestMap","null==="+map.get(null));
}
TestMap: {aaa=aaa}
TestMap: {null=null, aaa=aaa}
TestMap: aaa===aaa
TestMap: null===null
public void invoke(){
        Map map=new HashMap();
        map.put("aaa","aaa");
        map.put("a","aaa");
        map.put("aa","aaa");
        Log.d("TestMap",map.toString());
        //遍历Map
        Iterator iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            Log.d("TestMap", "Key = " + key + ", Value = " + value);
        }
}
TestMap: {aa=aaa, a=aaa, aaa=aaa}
TestMap: Key = aa, Value = aaa
TestMap: Key = a, Value = aaa
TestMap: Key = aaa, Value = aaa

2、LinkedHashMap带双向链表的哈希表结构,保持存取顺序,允许null键和null值,非线程安全,效率较高。

public void invoke(){
        Map maplink=new LinkedHashMap();
        maplink.put("aaa","123456789");
        maplink.put("aaa","123456789");
        maplink.put("aaa","123456789");
        maplink.put("aaa","123456789");
        Log.d("TestMap",maplink.toString());
}
TestMap: {aaa=123456789}

3、TreeMap平衡排序二叉树(红黑树)结构,按自然排序或比较器存入元素以保证元素顺序。非线程安全。

这篇文章主要巩固一下几种集合类相关的基础知识,也加深一下印象,如果文章中有错误有问题,欢迎指出,以后会日益完善。

你可能感兴趣的:(Java基础之集合 List、Map和Set)