一文让你看懂java集合之间的区别

集合相关知识

基础知识

  1. List Set Map都是接口,前两个继承至Collection接口,Map独立接口

    • List:允许重复、有序对象,可以插入null
    • Set:不允许重复,可以插入null、无序
    • Map:使用键值对存储。Map会维护与Key有关联的值。两个Key可以引用相同的对象,但Key不能重复。每个键只能映射一个值
  2. Map集合的数据结构针对键有效,跟值无关,Collection集合的数据结构针对元素有效。

  3. Set:元素不可以重复

    • HashSet:
      • 实现Set接口
      • 无序、唯一、非同步
      • 允许元素为NULL
      • 初始容量影响性能
      • 底层是HashMap,通过hashCode()和equals()来保证唯一性
    • LinkedHashSet:
      • 迭代是有序的
      • 允许为NULL
      • 底层实际上是一个HashMap+双向链表实例(实际是LinkedHashMap)
      • 非同步
      • 性能比HashSet要差,业务要维护一个双向链表
    • TreeSet:
      • 实现NavigableSet接口
      • 可以实现排序功能
      • 得出实际上是一个TreeMap实例
      • 非同步
      • 底层是红黑树(唯一,有序)自然排序和比较器排序来保证元素排序,
  4. List:有序,可重复,查询多用ArrayList,增删多用LinkedList

    • ArrayList:动态数组,空间浪费在预留,默认初始容量为10,扩容1.5倍

      源码阅读:https://blog.csdn.net/issunmingzhi/article/details/102795492

      • 优点:底层结构是数组,查询快,增删慢(需要数组的拷贝复制,navite方法由C/C++实现)

        关于增删慢不是绝对的,慢是慢在需要数组的拷贝与复制,如果一直增删末尾的话更快,删除中间的位置也是更快,但是一般来说都是慢的

      • 缺点:线程不安全,效率高

    • Vector:(过时)Object数组,使用较少几乎被ArrayList代替,两倍的扩容导致消耗更多内存

      • 优点:底层结构是数组,查询快,增删慢
      • 缺点:线程安全,效率低
    • LinkedList:

      • 优点:底层数据结构是双向链表(方便往前遍历),查询慢,增删快。
      • 缺点:线程不安全,效率高,不支持高效地随机访问,空间浪费在存储前后驱
  5. Map:

    • Hashtable:(过时)无序,方法是同步的,线程安全,效率低,不允许null,默认初始大小为11,扩容2n+1;

    • LinkedHashMap:

      • 继承自HashMap
      • 迭代有序
      • 非同步
    • HashMap:

      • 实现原理:
        • 由数据和链表组成,数组是hashmap的主体,链表主要是为了解决哈希冲突而存在的,如果定位到的数组位置不含链表,那么对于查找、添加等操作很快,只需要一次寻址即可;如果定位到的数组存在链表,对于添加操作,其时间复杂度为o,首先遍历链表,存在即覆盖;对于查找操作来讲,还需遍历链表,然后通过key对象的equals方法逐一查找。所以性能考虑,hahsMap中的链表出现越少,性能才会更好。
      • 是Hashtable的轻量级实现。底层结构是一个数组,数组中的每一项都是一条链表,无序,方法不是同步的,线程不安全,效率高,允许null(key和value都允许),能在查询和修改方便继承了数组的线性查找和链表的寻址修改;无contains方法;初始容量为16每次扩容为2n。当链表长度大于阈值8时将链表转化为红黑树,从而减少搜索时间

      源码阅读:https://blog.csdn.net/issunmingzhi/article/details/102958877

    • TreeMap:有序,基于红黑树,非线程安全

  6. Queue:PriorityQueue

  7. 迭代器Iterator:用于顺序访问集合对象的元素,无需知道集合对象的底层实现。Iterator 是可以遍历集合的对象,为各种容器提供了公共的操作接口,隔离对容器的遍历操作和底层实现,从而解耦。缺点是增加新的集合类需要对应增加新的迭代器类,迭代器类与集合类成对增加。

如何选用与使用

  • 根据需要确定集合的类型。如果是单列的集合,我们考虑用Collection下的子接口ArrayList和Set。如果是映射,我们就考虑用Map
  • 确定用哪个子类
    • 去找Tree红黑树类型的
    • 去找Linked双向链表结构的
    • 去找线程安全的集合类使用
    • 是否需要同步
    • 迭代时是否需要有序(插入顺序有序)
    • 是否需要排序(自然顺序或者手动排序)
  • 估算存放集合的数据量有多大,无论是List还是map,它们实现动态增长,都是有性能消耗的,在初始化时选择一个合理的容量会减少动态增长时的消耗
  • 使用泛型,避免在运行时出现ClassCastException
  • 尽可能使用Collections工具类,或者获取只读、同步或空的集合,而非自己实现

面试知识

  • ArrayList和Vector的区别

    • 共同点:都实现了List接口,都是有序集合,底层是数组。可以按位置索引号取出某个元素,运行元素重复和允许为NULL
    • 区别
      • 同步性:
        • ArrayList是非同步的
        • Vector是同步的
        • 即便需要同步的时候,我们可以使用Collections工具类来构件出同步的ArrayList而不用Vector
      • 扩容大小
        • Vector增长原来的一倍
        • ArrayList增长原来的0.5倍
  • HashMap和Hashtable的区别:

    • 共同点:从存储结构和实现来讲基本上都是相同的,都是实现Map接口
    • 区别:
      • 同步性:
        • HashMap是非同步的,线程不安全(通过修改数据时锁住整个HashTable)
        • Hashtable是同步的,线程安全
      • 是否允许为null
        • HashMap允许为null
        • Hashtable不允许为null
      • contain方法
        • Hashtable有contains方法
        • HashMap把Hashtable的contains方法去掉了,改成了containsValue和containsKey
      • 继承不同
        • HashMap继承自AbstractMap
        • Hashtable继承自Dictionary
  • List和Map区别

    • 共同点:没啥
    • 不同点:
      • 存储结构不同
        • List是存储单列的集合
        • Map存储的是key-value键值对的集合
      • 元素是否可重复
        • List允许元素重复
        • Map不允许key重复
      • 是否有序
        • List集合是有序的(存储有序)
        • Map集合时无须的(存储无序)
  • Collection和Collections的区别

    • Collection是集合的上级接口,继承它的有Set和List接口,接口的意义是为各种具体的集合提供了最大化的统一操作方式
    • Collections是集合的工具,提供了一系列的静态方法对集合的搜索、查找、同步等操作
  • ArrayList,LinkedList的存储性能和特性

    首先ArrayList的底层是数组,LinkedList的底层是双向链表

    • ArrayList它支持以角标位置进行索引出对应的元素(随机访问),而LinkedList则需要遍历整个链表来获取对应的元素。因此一般来说ArrayList的访问速度是要比LinkedList要快的
    • ArrayList由于是数组,对于删除和修改而言消耗是比较大(复制和移动数组实现),LinkedList是双向链表删除和修改只需要修改对应的指针即可,消耗是很小的。因此一般来说LinkedList的增删速度是要比ArrayList要快的
  • Enumeration和Iterator接口的区别

    • Iterator的方法名比Enumeration更科学
    • Iterator有fail-fast机制,比Enumeration更安全,当一个集合正在被遍历的时候,它会阻止其他线程去修改集合
    • Iterator能够删除元素,Enumeration并不能删除元素
  • Listlterator特点

    • 继承Iterator接口,它用于遍历List集合的元素
    • 可以实现双向遍历,添加元素,设置元素
  • Iterator 和 ListIterator 有什么区别

    • 相同点:都是迭代器,当需要对集合中元素进行遍历不需要干涉其遍历过程时,这两种迭代器都可以使用

    • 不同点:

      • 使用范围不同,Iterator可以应用于所有的集合,Set、List和Map和这些集合的子类型。而ListIterator只能用于List及其子类型。

      • ListIterator有add方法,可以向List中添加对象,而Iterator不能。

      • ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator不可以。

      • ListIterator可以定位当前索引的位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。

      • 都可实现删除操作,但是ListIterator可以实现对象的修改,set()方法可以实现。Iterator仅能遍历,不能修改。

  • 并发集合类是什么?

    • java1.5并发包(java.util.concurrent)包含了线程安全集合类,允许在迭代时修改集合
    • 迭代器被实际为fail-fast的,会抛出ConcurrentModificationException
    • 一部分类为
      • CopyOnWriteArrayList
      • ConcurrentHashMap
      • CopyOnWriteArraySet
  • java中HashMap的key值要是为类对象则该类需要满足什么条件

    • 需要同时重写该类的hashCode()方法和它的equals()方法
      • 在源码中,在插入元素的时候是先算出改对象的hashCode。如果hashCode相等的话,那么表明该对象是存储在同一个位置上的
      • 如果调用equals()方法,两个key相同,则替换元素
      • 如果调用equals()方法,两个key不相等,则说明该hashCode仅仅是碰巧相同,此时是散列冲突,将新增的元素放在桶子上
  • Array和ArrayList区别:

    • Array:
      • 可以包含基本类型和对象类型
      • 大小固定
    • ArrayList
      • 只能包含对象类型
      • 大小动态变化
      • 提供了更多的方法和特性
  • 在Queue中

    • poll()和remove()有什么区别都是从队列中删除第一个元素。如果队列元素为空,调用remove() 的行为与 Collection 接口的版本相似会抛出异常,但是新的 poll() 方法在用空集合调用时只是返回 null**。因此新的方法更适合容易出现异常条件的情况。
    • add()和offer()区别:**add()**和offer()都是向队列中添加一个元素。一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,调用 add() 方法就会抛出一个 unchecked 异常,而调用 offer() 方法会返回 false。因此就可以在程序中进行有效的判断!
发布了47 篇原创文章 · 获赞 35 · 访问量 3244

猜你喜欢

转载自blog.csdn.net/issunmingzhi/article/details/103489773