[Java collection source code] Several questions about ArrayList

1. Talk about the understanding of ArrayList?

ArrayList has a lot of content. You can start with the overall structure first, and then use a certain detail as a breakthrough, such as this: The underlying data structure of ArrayList is an array, and its API has made a layer of access to the bottom of the array, such as the process of the add method. Yes... (For details, please refer to the add process in ArrayList source code analysis ).

In addition, the understanding of LinkedList is the same.

2. Issues related to expansion

2.1 ArrayList has no parameter constructor construction, now add a value in, what is the size of the array at this time, and what is the maximum available size before the next expansion?

Answer: The size of the array here is 1, and the maximum available size before the next expansion is 10, because the ArrayList has a default value when it is expanded for the first time. The default value is 10. When a value is added for the first time, the array The available size of has been expanded to 10.

2.2 If you continuously add values ​​to the list and increase to the 11th, what is the size of the array?

Answer: The actual question here is the expansion formula. When it is increased to 11, we hope the size of the array is 11 at this time, but in fact the maximum capacity of the array is only 10. If it is not enough, expansion is needed. The expansion formula is: oldCapacity + (oldCapacity>> 1), oldCapacity represents the existing size of the array. The current scenario calculation formula is: 10 + 10 /2 = 15. Then we find that 15 is enough, so the size of the array will be expanded to 15.

2.3 Array initialization, after adding a value, if you use the addAll method to add 15 values ​​at once, what is the size of the final array?

Answer: In the previous question, it has been calculated that after adding a value to the array, the actual size is 1, and the maximum available size is 10. Now we need to add 15 values ​​at once, then we expect the size of the array to be 16. The maximum available size is only 10, which is obviously not enough. It needs to be expanded. The expanded size is: 10 + 10 /2 = 15. At this time, it is found that the expanded size is still less than the expected value of 16. At this time, there is a strategy in the source code as follows :

// newCapacity 本次扩容的大小,minCapacity 我们期望的数组最小大小
// 如果扩容后的值 < 我们的期望值,我们的期望值就等于本次扩容的大小
if (newCapacity - minCapacity < 0)
    newCapacity = minCapacity;

So the final size of the array after expansion is 16. For specific source code, please refer to the grow method of ArrayList source code analysis .

2.4 There is a very large array that needs to be copied. The size of the original array is 5k. How to copy quickly?

Answer: Because the original array is relatively large, if you do not specify the size of the array when creating a new array, it will be expanded frequently. Frequent expansion will involve a lot of copy work, resulting in low copy performance. Therefore, when creating a new array, specify the new The size of the array is 5k.

2.5 Why do I say that capacity expansion consumes performance?

Answer: The bottom layer of the expansion uses the System.arraycopy method, which will copy all the data of the original array to the new array, so the performance consumption is more serious.

2.6 What can be learned from the source code expansion process?

Answer: There are two points:

  • The idea of ​​expansion is worth learning. Through automatic expansion, users don’t need to care about the changes in the underlying data structure. The package is well packaged. The 1.5 times expansion speed can make the expansion speed increase slowly in the early stage and faster in the later stage. In most work, the value of the array is not very large, so the slow growth in the early stage is conducive to saving resources, and the rapid expansion can also be achieved when the growth rate is faster in the later stage.
  • During the expansion process, there is a sense of array size overflow. For example, it is required that the expanded array size cannot be less than 0 and cannot be greater than the maximum value of Integer.

3. Delete related questions

3.1 There is an ArrayList, the data is 2, 3, 3, 3, 4, and there are three 3s in the middle. Now through for (int i=0;i<list.size ();i++), I want to set the value to 3 Element deletion, can I delete it cleanly? What is the result of the final deletion and why? The delete code is as follows:

List<String> list = new ArrayList<String>() {
    
    {
    
    
  add("2");
  add("3");
  add("3");
  add("3");
  add("4");
}};
for (int i = 0; i < list.size(); i++) {
    
    
  if (list.get(i).equals("3")) {
    
    
    list.remove(i);
  }
}

Answer: It cannot be deleted cleanly. The final result of deletion is 2, 3, 4, and a 3 cannot be deleted. The reason is
image descriptionthat we can see the following figure: we can see from the figure that every time an element is deleted, the elements behind the element It will move forward, and the i of the loop is constantly growing at this time, which will eventually cause the last 3 of the 3 to be deleted every time to be missed, resulting in failure to delete.

3.2 Or the above ArrayList array, we can delete it by enhancing the for loop, can it?

Answer: No, an error will be reported. Because the enhanced for loop process actually calls the next () method of the iterator, when you call the list.remove () method to delete, the value of modCount will be +1, but at this time the value of expectedModCount in the iterator has not changed , Resulting in the next time the iterator executes the next () method, expectedModCount != modCount will report ConcurrentModificationException error.

3.3 The above array is still the same. Can it be deleted using the Iterator.remove () method when deleting, and why?

Answer: Yes, because the Iterator.remove () method will assign the latest modCount to expectedModCount during its execution, so that in the next cycle, both modCount and expectedModCount will be equal.

3.4 Do the above three questions have the same result for LinkedList?

Answer: Yes, although the underlying structure of LinkedList is a doubly linked list, for the above three questions, the results are consistent with ArrayList.

4. Compared with LinkedList

4.1 What is the difference between ArrayList and LinkedList?

Answer: You can start with the underlying data structure, and then use a certain method as a breakthrough point, such as:

  • The biggest difference is that the bottom data structure of the two is different. The bottom layer of ArrayList is an array, and the bottom layer of LinkedList is a doubly linked list.
  • The difference in the data structure of the two also leads to differences in the API implementation of the operation. Take the new implementation as an example, ArrayList will first calculate and decide whether to expand, and then directly assign the new data to the array, while LinkedList only needs Just change the positional relationship between the inserted node and its front and back nodes.

4.2 What is the difference between ArrayList and LinkedList application scenarios?

answer:

  • ArrayList is more suitable for fast search and matching, and is not suitable for frequent additions and deletions. It is more suitable for scenarios where elements are often matched and inquired in work.
  • LinkedList is more suitable for scenarios where there are frequent additions and deletions, but few queries.

4.3 Is there a maximum capacity for ArrayList and LinkedList?

answer:

  • ArrayList has the largest capacity, which is the maximum value of Integer. JVM will not allocate memory space for the array if it is larger than this value.
  • The bottom layer of LinkedList is a doubly linked list, which can be infinite in theory. However, in the source code, the actual size of the LinkedList uses the int type, which also shows that the LinkedList cannot exceed the maximum value of Integer, or it will overflow.

4.4 How do ArrayList and LinkedList handle null values?

answer:

  • ArrayList allows the addition of null values ​​and the deletion of null values. When deleting a null value, start from the beginning and delete the element whose first value is null
  • When LinkedList is added or deleted, there is no special check for null value, and it is allowed to add and delete.

5. Thread safety issues

5.1 Are ArrayList and LinedList thread-safe and why?

answer:

  • When the two are used as non-shared variables, for example, when they are only local variables in the method, there is no thread safety problem. Only when the two are shared variables, there will be thread safety problems.
  • The main problem is that in a multithreaded environment, all threads can operate on arrays and linked lists at any time, which can lead to values ​​being overwritten and even confusion. Just like the elementData, size, and modConut of ArrayList itself are not locked when performing various operations, and the types of these variables are not visible (volatile), so if multiple threads operate on these variables, there may be The value is overwritten.

If there are thread safety issues, ConcurrentModificationException will be reported frequently during the iteration process, which means that the structure of the array or linked list has been modified by other threads during my current loop.

5.2 How to solve thread safety issues?

Answer: It is recommended to use Collections#synchronizedList to solve the problem in the Java source code. The return value of Collections#synchronizedList is that each method of List has a synchronized lock, which ensures that at the same time, the array and linked list can only be modified by one thread, but the performance Greatly reduce, the specific source code:

public boolean add(E e) {
    
    
    synchronized (mutex) {
    
    // synchronized 是一种轻量锁,mutex 表示一个当前 SynchronizedList
        return c.add(e);
    }
}

In addition, you can also use JUC's CopyOnWriteArrayList concurrent List to solve.

Guess you like

Origin blog.csdn.net/weixin_43935927/article/details/108721887