Without further ado, let’s go directly to the picture:
Java collections, also called containers, Mainly derived from two major interfaces (Interface)
: Collection and Map
As the name suggests, containers are used to store data.
The difference between these two interfaces is:
That is, singles are placed in the Collection, and couples are placed in the Map. (So where do you belong?
Learning these collection frameworks, I think there are 4 goals:
Regarding Map, the previous HashMap article has been very thorough and detailed. So I won’t go into details in this article. If you haven’t read that article yet, please go to the official account and reply “HashMap” to read the article~
Let’s first look at the top-level Collection.
Collection also defines many methods, which will also be inherited into each sub-interface and implementation class. The use of these APIs is also a common test in daily work and interviews, so Let’s look at these methods first.
The collection of operations is nothing more than the four categories of "Add, Delete, Modify and Check", also called CRUD
:
Create, Read, Update, and Delete.
Then I also divide these APIs into these four categories:
Function | Method |
---|---|
Add | add()/addAll() |
Delete | remove()/ removeAll( ) |
Change | There is no |
in Collection Interface#check | contains()/ containsAll() |
Others | isEmpty()/size()/toArray() |
Let’s look at it in detail below:
boolean add(E e);
add()
The data type passed in by the method It must be Object, so when writing basic data types, auto-boxing and unboxing will be performed.
There is another method addAll()
, which can add elements from another collection to this collection.
boolean addAll(Collection<? extends E> c);
boolean remove(Object o);
remove()
is the specified element to be deleted.
That corresponds to addAll()
,
naturally has removeAll()
, which is to delete all elements in set B.
boolean removeAll(Collection<?> c);
There is no direct operation to change elements in Collection Interface. Anyway, deletion and addition can complete the change!
boolean contains(Object o);
boolean containsAll(Collection<?> c);
boolean isEmpty();
int size();
Object[] toArray();
以上就是 Collection 中常用的 API 了。
在接口里都定义好了,子类不要也得要。
当然子类也会做一些自己的实现,这样就有了不同的数据结构。
那我们一个个来看。
List 最大的特点就是:有序
,可重复
。
看官网说的:
An ordered collection (also known as a sequence).
Unlike sets, lists typically allow duplicate elements.
This time I also mentioned the characteristics of Set. It is completely opposite to List. Set is unordered
and does not repeat
.
List can be implemented in two ways: LinkedList and ArrayList. The most common question asked during interviews is how to choose between these two data structures.
For this type of selection problem:
The first is to consider whether the data structure can complete the required functions;
If both can be completed, the second is to consider which is more Efficient.
(Everything is like this.
Let’s look specifically at the APIs of these two classes and their time complexity:
Function | Method | ArrayList | LinkedList |
---|---|---|---|
increase | add(E e) | O(1) | O(1) |
Add | add(int index, E e) | O(n) | O(n) |
Delete | remove(int index) | O(n) | O(n) |
Delete | remove(E e) | O(n) | O(n) |
Change | set(int index, E e) | O(1) | O(n) |
Check | get(int index) | O(1) | O(n) |
A few explanations:
add(E e)
is to add elements to the tail. Although the ArrayList may expand, the amortized time complexity ) is still O(1).
add(int index, E e)
is to add an element at a specific position. LinkedList needs to find this position first and then add this element. Although it is a simple "add" action It's O(1), but finding this position is still O(n). (Some people think this is O(1). Just explain it clearly to the interviewer and refuse to take the blame.
remove(int index)
is the element on the index of remove. So
remove(E e)
is the first element seen by remove, then
What is the reason for the difference in time complexity?
Answer:
Because ArrayList is implemented using arrays.
The biggest difference between arrays and linked lists is that arrays can be accessed randomly (random access).
This feature causes You can get the number at any position in O(1) time through subscripting, but you can't do that with a linked list. You can only traverse it one by one from the beginning.
That is to say, in the two functions of "Change and Check" Because the array can be accessed randomly, ArrayList is highly efficient.
What about "addition and deletion"?
If you do not consider the time to find this element,
Because of the physical continuity of the array, when you want to add or delete elements, it is fine at the tail, but other places will cause subsequent elements to be deleted. Movement, so the efficiency is lower; while a linked list can easily disconnect from the next element, directly insert new elements or remove old elements.
But, in fact, you have to consider the time to find the element. . . And if it is operated at the tail, ArrayList will be faster when the amount of data is large.
So:
As the last knowledge point about List, let’s talk about Vector. This is also an age-revealing post, used by all the big guys.
The Vector, like the ArrayList, also inherits from java.util.AbstractList
But it has been deprecated now because...it adds too many synchronized!
Every benefit comes at a cost. The cost of thread safety is low efficiency, which can easily become a bottleneck in some systems. Therefore, now we no longer add synchronized at the data structure level, but instead Transfer to our programmers==
So the common interview question: What is the difference between Vector and ArrayList? Just answering this is not very comprehensive.
Let’s take a look at the high-voted answers on stack overflow:
The first is the thread safety issue just mentioned;
The second is the difference in how much expansion is required during expansion.
You have to look at the source code for this:
This is the expansion implementation of ArrayList. This arithmetic right shift operation is to The binary number of this number is moved one bit to the right, and the leftmost complements the sign bit , but because the capacity does not have a negative number, it still adds 0.
The effect of shifting one bit to the right is to divide by 2 , then the new capacity defined is 1.5 times of the original capacity.
Let’s look at Vector again:
Because usually we do not define capacityIncrement, so by default it is expanded twice.
If you answer these two points, there will definitely be no problem.
Queue is a linear data structure with one end in and the other out; and Deque is both ends. All can be entered and exited.
The Queue interface in Java is a little bit confusing. Generally speaking, the semantics of queues They are all first in, first out (FIFO).
But there is an exception here, that is, PriorityQueue, also called heap, does not come out in the order of the time it enters, but goes out according to the specified priority, and its operation is not O(1), time The calculation of complexity is a bit complicated, and we will discuss it in a separate article later.
The Queue methodOfficial website[1]It’s all summarized. It has two sets of APIs, and the basic functions are the same, but:
Function | Throw exception | Return value |
---|---|---|
Add | add(e) | offer(e) |
remove() | poll() | |
element() | peek() |
Throws an exception | Return value | |
---|---|---|
addFirst(e)/ addLast(e) | offerFirst( e)/ offerLast(e) | |
removeFirst()/ removeLast() | pollFirst()/ pollLast() | |
getFirst()/ getLast() | peekFirst()/ peekLast() |