ArrayList (expansion mechanism)

I. Introduction

You may not be unfamiliar with the ArrayList collection, but do you know the expansion mechanism of the ArrayList collection? Let's focus today

2. ArrayList expansion mechanism

1. What scenarios is it suitable for?

Retrieve more scenes

2. Features of ArrayList

1. The bottom layer of the ArrayList collection adopts the data structure of data, which is Object type.
2. The default initial capacity of ArrayList is 10, and the expansion factor is 1.5.
3. It is recommended to give a pre-estimated initial capacity to reduce the number of array expansions. This is The ArrayList collection is an important optimization strategy. Because the data in the original array needs to be copied to the new array while expanding the capacity, but if a large amount of data needs to be inserted, the form of the assignment array is very inefficient, so in most cases it will be used Constructor with parameters, pass in a pre-estimated capacity, and define the capacity in advance.
4. ArrayList is not thread-safe

import java.util.ArrayList;
import java.util.List;

public class ListTest {
    
    
public static void main(String[] args) {
    
    
    List<String> list = new ArrayList<String>();
    list.add("b");//第一个,索引下标0
    list.add("d");
    list.add("c");
    list.add("a");
    list.add("d"); //允许使用重复元素

    System.out.println(list);  //输出结果:[b, d, c, a, d]
    System.out.println(list.get(2));  //输出指定下标的元素,输出结果:c

    list.add(1,"f");//在指定索引下标位置添加元素
    System.out.println(list); //输出结果:[b, f, d, c, a, d],原来下标为1和1之后的下标索引位置的元素自动向后移动

    List<String> a = new ArrayList<String>();
    a.add("123");
    a.add("456");
    list.addAll(2,a);  //在指定索引下标的位置插入集合
    System.out.println(list);//输出结果:[b, f, 123, 456, d, c, a, d]

    //获取指定元素在集合中第一次出现的索引下标
    System.out.println(list.indexOf("d")); //输出结果:4
    //获取指定元素在集合中最后一次出现的索引下标
    System.out.println(list.lastIndexOf("d"));//输出结果:7

    list.remove(2);  //根据指定的索引下标移除元素
    System.out.println(list);  //输出结果:[b, f, 456, d, c, a, d]

    list.set(1,"ff"); //根据指定的索引下标修改元素
    System.out.println(list); //输出结果:[b, ff, 456, d, c, a, d]

    //根据索引下标的起始位置截取一段元素形成一个新的集合,截取的时候,包含开始的索引不包含结束时的索引
    List<String> sublist= list.subList(2,4);
    System.out.println(sublist);//输出结果:[456, d]

    System.out.println(list.size());//输出结果7
    }
}
import java.util.LinkedList;
import java.util.List;

public class ListTest {
    
    
public static void main(String[] args){
    
    
    List l1 = new LinkedList();
    for(int i = 0;i<=5;i++){
    
    
    l1.add("a"+i);
    }

    System.out.print(l1);
    l1.add(3,"a100");
    System.out.println(l1);
    l1.set(6,"a200");
    System.out.println(l1);
    System.out.print((String)l1.get(2)+" ");
    System.out.println(l1.indexOf("a3"));
    l1.remove(1);
    System.out.println(l1);
    }
}

Output result:

[a0,a1,a2,a3,a4,a5]

[a0,a1,a2,a100,a3,a4,a5]

[a0,a1,a2,a100,a3,a4,a200]

a2 4

[a0,a2,a100,a3,a4,a200]

3. ArrayList expansion mechanism

Before using ArrayList, there is no need to define the size space in advance like an array. The capacity will automatically increase with use. Then why does the bottom layer need to judge whether the capacity of the collection can hold the elements to be added when using the add method of ArrayList to add elements? Woolen cloth? Wouldn't it be good to just put it in without defining a fixed size?

The add method is divided into three steps:
①. Determine whether the collection capacity satisfies the added element
②, add element
③, collection length + 1
insert image description here
Answer:
The user does not need to define the size in advance, because the bottom layer has already defined the size by default. In fact, there is a boundary value, not infinite growth. When used, it increases because the bottom layer has an expansion factor (the expansion factor is 1.5), and it will expand when the number reaches a certain percentage of the array. The default initial size of ArrayList is 10
insert image description here
insert image description here

Question: You can think about why the underlying expansion factor of ArrayList is 1.5? Why not 1.3, 2.4...?

The underlying expansion factor of ArrayList is 1.5, not other numbers, in order to find a suitable compromise between memory usage and performance. Here are some reasons:

3.1. Efficiency of memory allocation:

The choice of expansion factor will affect the efficiency of memory allocation. If the expansion factor is too small, each expansion will only increase a small amount of capacity, which will lead to frequent memory allocation operations and increase the time and space overhead. And if the expansion factor is too large, each expansion will increase a large amount of capacity, which may lead to excessive waste of memory. 1.5 is a relatively small expansion factor that can balance memory usage and performance to a certain extent.

3.2. The cost of data migration

When the ArrayList needs to be expanded, the original data needs to be migrated to a new larger array. The choice of expansion factor will affect the frequency and cost of data migration. A smaller scaling factor results in more frequent data migrations, while a larger scaling factor reduces the number of data migrations. As a relatively small expansion factor, 1.5 can reduce the cost of data migration to a certain extent.

3.3, the balance between performance and space

ArrayList is designed to provide efficient random access and dynamic growth capabilities. Choosing 1.5 as the expansion factor can balance performance and space requirements to a certain extent. A smaller expansion factor can reduce memory waste, while a larger expansion factor can reduce the frequency of memory allocation.

To sum up, the characteristics of ArrayList are as follows

  • Initial capacity: When you create an ArrayList object, it will allocate an initial capacity (the default is 10, you can set the initial capacity through the constructor). This initial capacity indicates the number of elements that the array inside the ArrayList can hold.
  • Adding elements: When you add elements to the ArrayList, it first checks whether it needs to be expanded. This is done by comparing the number of elements inside the ArrayList with the current capacity.
  • Expansion conditions: Usually, ArrayList will trigger an expansion operation when the number of elements reaches the current capacity. When the number of elements is equal to or exceeds the current capacity, ArrayList will start the expansion mechanism
  • Capacity expansion strategy: ArrayList will create a new and larger array. Usually, the capacity of the new array will be 1.5 times the current capacity (this multiple can be adjusted through the ensureCapacity method or the parameters of the constructor). ArrayList will then copy all existing elements into the new array.
  • Copying elements: Copying elements into a new array can use the System.arraycopy method or a similar mechanism. The time complexity of this operation is O(n), where n is the number of elements.
  • Update Capacity: Once all elements are copied into the new array, ArrayList will point the internal array reference to the new array and update the capacity to the capacity of the new array.
  • Adding new elements: Finally, the ArrayList will add the new elements to the new array, which is now large enough to hold all the elements.
  • Expansion cost: Since the expansion operation needs to copy elements to the new array, it will introduce some performance overhead. In order to reduce the frequency of expansion, you can usually specify a sufficiently large initial capacity when creating an ArrayList to avoid multiple expansions.

3. Summary

The expansion mechanism of ArrayList is automatically managed, and it will dynamically expand the capacity of the internal array when needed to accommodate the increasing number of elements. This mechanism ensures that the ArrayList can maintain efficient performance when adding elements, but it also needs to consider the performance overhead that may be introduced by the expansion operation. Therefore, when processing a large amount of data, you can manually set a sufficiently large initial capacity to reduce the number of expansions and improve performance.

Guess you like

Origin blog.csdn.net/wmj20001225/article/details/132630488