让我们通俗的理解一下Java中的集合
这是一篇用于速记和通俗理解的文章,有不严谨的地方欢迎指出来,反正我不一定改。
先来挂一张Java集合的鸟瞰图(俯视图?框架图?)。
图片转载自:面试常被问到的 Java 集合知识点(详细)
接下来我们通俗的理解一下
我们使用Java语言进行开发,设计了类,那么肯定是需要一种东西来装载这些类的对象。于是Java设计了 集合 和 Map 来做这件事。PS:Java容器里只能放对象,对于基本类型(int, long, float, double等),需要将其包装成对象类型后(Integer, Long, Float, Double等)才能放到容器里。很多时候拆包装和解包装能够自动完成。这虽然会导致额外的性能和空间开销,但简化了设计和编程。
集合(Collection)负责存储一个元素集合,而图(Map)负责存储键/值对映射。
但是集合和Map能表达的很有限。
- 我们对集合内元素的放置提出了要求:
- 来收集有序的且允许有重复元素的Collection,于是有了 List。
- 来收集无序的且不包含重复元素的Collection,于是有了 Set。
- 我们对集合的存取提出了要求:
- 希望读取的对象,顺序进入,顺序取出,即先进先出,于是有了 Queue。
- 希望读取的对象,顺序进入,逆序取出,即先进后出,于是有了 Stack。
- 我们对Map内元素的放置提出了要求:
- 如果按照 hash 的方式进行放置,于是有了 HashMap。
- 如果按照 二叉平衡树 的方式进行放置,于是有了 SortedMap 和 TreeMap。
好了,在上面,我们一共提到了六大种容器,分别是:List、Set、Queue、Stack、HashMap、TreeMap。
- 对于List,我们提出了更进一步的要求:
- 按照数组方式实现List,于是有了 ArrayList。
- 按照双向循环链表方式实现List,于是有了 LinkedList。
- 对于HashMap,我们提出了更进一步的要求:
- 既能够保留hash的存取方式,又能够像LinkedList一样记录元素的插入顺序,于是有了 LinkedHashMap。
- 对于一些缓存的场景,我们希望旧数据能自己消失,于是有了 WeakHashMap。
- 对于TreeMap,我们提不出更进一步的要求了。
- 对于Set,我们提出了更进一步的要求:
- 按照Hash的方式存取数据,于是有了HashSet,本质上是包装了 HashMap。
- 按照AVL的方式存取数据,于是有了TreeSet,本质上是包装了 TreeMap。
- 既有Hash的存取方式,又能够像LinkedList一样记录元素的插入顺序,于是有了LinkedHashSet,,本质上是包装了 LinkedHashMap。
- 对于Queue,我们提出了更进一步的要求:
- 按照 优先队列 的方式存取数据,于是有了 PriorityQueue,
- 按照一个既可以当队列又可以当栈的方式存取数据,于是有了双端队列:DeQueue。
- DeQueue如果按照数组的方式实现,于是有了 ArrayDeque。
- 对于Stack,我们提不出更进一步的要求了,但是我们希望你用DeQueue来实现栈和队列。
进入并发快车道
对于上述提及的容器,很多是不可以用在高并发环境下的,会有线程安全问题,对于常用的容器,我们在Java并发包下,列出了并发版本的容器。
-
先说说HashMap
- HashMap比较快,但是线程不安全,于是引入了 HashTable,通过Synchronize加锁的方式,变得线程安全,但是牺牲了效率,于是又引入 ConcurrentHashMap ,通过分段锁的方式,既保证了安全性有提升了效率。
-
还有ArrayList
- ArrayList不是线程安全的,于是有了 Vector,通过 Synchronize 加锁的方式,变得线程安全。
-
再说说Queue
- BlockingQueue、BlockingDeque、
- ArrayBlockingQueue、LinkedBlockingDeque、LinkedBlockingQueue、
- ConcurrentLinkedDeque、ConcurrentLinkedQueue、
- DelayQueue、PriorityBlockingQueue
-
最后说说List
- CopyOnWriteArrayList、CopyOnWriteArraySet