【java】集合之 Collection


Rolling on the floor laughingWinking smileVampire bat


  image

  1、List

     List的有三个实现,ArrayList、LinkedList、Vector,CopyOrWirteArrayList也是List接口的实现,但是它属于 concurrent包下面的,concurrent单独讲。

      image

  • ArrayList 是怎么扩容的?

      当当前的容量无法再继续添加元素的时候,进行扩容,新扩充的容量 等于 之前的 1.5倍,也就是说扩容因子为 1.5。

  • ArrayList、Vector中的 RandomAccess

      RandomAccess 是一个标志接口(Marker interface) 表明数据结构能够进行快速随机访问,也就是下标访问,而LinkedList就不支持,

      它需要进行耗时的查询,找到对应的元素。

  • 如果要添加1W个元素,怎么提高效率?

      新建一个1W大小的数组,先将数据填到这个数组里,然后就数组转化成ArrayList,网上有些说法直接构建一个大小为1W的ArrayList,然后通过add,这个方法固然是可以的,但是会多出很多次函数调用1W次 add,1W次ensureCapacityInternal,1W次ensureExplicitCapacity,而直接构建数组可以省去这些函数调用,因为本身ArrayList就是在维护一个数组。

  • ArrayList中的 fail-fast机制

      fail-fast发生在A、B两个线程同时访问一个通过游标访问一个ArrayList,一个是访问,一个删除,导致异常,为了避免异常,可以采用java.util.concurrent里的CopyOrWriteArrayList。

  • vector 是如何保证线程安全的

      是通过给方法添加 同步锁实现的,但这样的效率很低,如果两个线程都要遍历,那么第二个需要等第一个遍历完之后才能开始遍历,vector已经过时,如果要想要线程安全,最好是用CopyOrWriteArrayList

  • vector 设置扩容因子

      vector的默认扩容因子是2,也就是说每次扩容,都会扩大到原来的两倍,同时它还可以支持自定义扩容因子,实际扩容的时候扩容因子等于 1+ 自定义扩容因子

  • ArrayList和LinkedList的不同适用场景

      ① 因为ArrayList是顺序存储的,那么它随机访问的效率很高,但是插入或者删除的时候,为了保存存储的顺序秩序,必须对原数据重新拷贝,效率较低,但LinkedList的元素是首位相接的,访问元素的时候,需要移动指针,遍历所有元素,随机访问效率就很低了,但如果是在某个数据前后插入数据,则只需要修改元素的前驱和后驱就能完成,效率很快。

      ② ArrayList在添加数据的时候,存在扩容现象,每次扩容都存在内容的重新分配和数据拷贝,导致效率低下,而LinkedList就不存在。

      频繁删除插入的引用场景,选择LinkedList,而倾向于查询的情况下,用ArrayList。

  • 避免空指针

     返回零长度的集合或者数组,而不是返回一个 null ,这样可以防止底层集合是空的。

  • 使用迭代器->迭代器模式

      https://www.cnblogs.com/jimmyai/p/design_pattern_iterator.html

  • Stack中的pop和peek

      pop和peek都能返回栈顶元素,但pop会讲栈顶元素推出栈,而peek不会。


2、Set

    set有三个直接的实现,TreeSet、HashSet和EnumSet,这三者差别较大,适用场景区别也较大。

  • 三者的特点

      HashSet内部维护着一个HashMap,它利用了HashMap的key值不可重复性来保证存储数据的不可重复性,每次查找的时候,它都需要先计算对象的hash值,然后再在对应的位置上查找,性能相对于ArrayList来说要差很多,但比LinkedArrayList要好,因为查找某个元素,不用遍历所有元素。

      TreeMap内部维护着NavigableMap,navigableMap实现了SortedMap接口,内部数据是有序的;

      EnumSet是一个专门用于枚举元素的排序,它只能添加一个枚举类型的枚举值,null也无法添加,对于EnumSet来说,枚举值是有序的,顺序就是枚举值定义的顺序,它与HashSet、TreeSet内部实现不同,采用的位向量方式存储数据。

  • HashSet和LinkedHashSet

      LinkedHashSet是HashSet的一个子类,与HashSet不同的是,它内部维护的是一个LinkedHashMap,数据存储与HashSet类似,不同的是LinkedHashSet中的元素与元素之间,有通过链表维护插入顺序,保证在遍历的顺序与插入顺序一致,但HashSet就无法保证顺序一致。

  • TreeSet排序

      TreeSet内部采用的是红黑树排序,在Map章节会着重讲解。

  • EnumSet性能最强,内存占用最低

      EnumSet采用的是位向量方式存储对象,每个枚举值代表着不同的位,EnumSet 里有没有值,是通过位是1或者0来表示的,不是存储实际的枚举值,查询的时候,值需要通过位或对应的位实现,所以性能是最强的,同时内存占用也是最低的。

  • Set的并发安全

      Set的安全性取决于它内部实现,因为TreeSet和HashSet内部都是由Map实现,所以其并发安全,直接取决于内部Map的并发安全能力,所以都是并发不安全的,如果要保证安全,可以通过Collections.newSetFromMap来构造一个并发安全的Set,参数传入一个并发安全的Map,它内部其实就是重新通过传入的map重新实现了Set,并发安全的Map在后面章节中讲。


3、Queue

    Queue

原文地址:https://www.cnblogs.com/jimmyai/p/java_collection.html