ArrayList의 동적 확장 메커니즘과 응용에 대한 심층적인 이해

자바 프로그래밍에서는 데이터 구조가 중요한 역할을 하는데, 흔히 사용되는 동적 배열인 ArrayList는 데이터 처리 시 편의성을 제공합니다. 그중에서도 독특한 동적 확장 메커니즘으로 인해 다양한 응용 분야에서 활용되고 있습니다. 직장에서든 인터뷰에서든 우리는 ArrayList를 만나게 될 것입니다. 이 기사에서는 ArrayList의 동적 확장 메커니즘을 직장이나 인터뷰에서 사용할 수 있도록 깊이 탐구할 것입니다.

ArrayList 소개

ArrayList는 Java 프로그래밍 언어의 클래스로 List 인터페이스를 구현하고 하단의 배열에 요소를 저장합니다. List에 요소 추가(add), 삭제(remove), 가져오기(get) 등의 기능을 제공합니다. 단점은 요소를 연속적으로 저장해야 하므로 추가, 삭제가 느리지만 쿼리가 빠르다는 장점이 있습니다. ArrayList에는 동적 확장 특성이 있습니다. 즉, 다양한 수의 요소를 수용하기 위해 필요에 따라 내부 배열의 크기를 자동으로 조정할 수 있습니다.

동적 확장에 대한 자세한 설명

ArrayList에 요소를 추가하면(add() 또는 addAll() 호출) 메소드가 ensureCapacityInternal()호출 됩니다.

소스 코드를 살펴보겠습니다:

추가하다()

public boolean add(E e) {
    
    
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

모두 추가()

public boolean addAll(Collection<? extends E> c) {
    
    
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount
    System.arraycopy(a, 0, elementData, size, numNew);
    size += numNew;
    return numNew != 0;
}

소스 코드에서 볼 수 있듯이 두 메서드 모두 ensureCapacityInternal()이 메서드를 호출하며 매개 변수는 현재 목록의 길이에 삽입할 개체 수를 더한 값입니다(단일 개체의 경우 1, 개체 모음의 경우 컬렉션 길이). )(컬렉션) 요소를 추가하는 데 필요한 최소 길이

보장용량내부()

private void ensureCapacityInternal(int minCapacity) {
    
    
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

ensureExplicitCapacity()메소드의 입력 매개변수 calculateCapacity()(매개변수는 실제 요소를 저장하는 배열과 컬렉션에 요소를 추가하는 데 필요한 최소 길이)와 메소드에서 처리되는 값입니다.

계산용량()

private static int calculateCapacity(Object[] elementData, int minCapacity) {
    
    
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
    
    
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}

현재 메서드에서 반환하는 값은 소스 컬렉션이 비어 있는 경우 기본 용량(10)과 요소 컬렉션에 요소를 추가하는 데 필요한 최소 길이 값 중 큰 값을 비교하고, 비어 있지 않으면 minCapacity를 반환합니다. .

_20230828230112.png

명시적 용량() 보장

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

자라다

private void grow(int minCapacity) {
    
    
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

이 코드를 자세히 설명하자면

  • int oldCapacity = elementData.length;

현재 요소를 저장하고 있는 배열의 길이인 elementData 배열의 길이인 현재 배열의 용량을 가져옵니다.

  • int newCapacity = oldCapacity + (oldCapacity >> 1);

새로운 용량을 계산합니다. 여기서 비트 연산은 1비트만큼 오른쪽으로 이동(2로 나누는 것과 동일)하여 현재 용량을 1.5배로 확장하는 데 사용됩니다. 비트 연산자에 대해 잘 모른다
면 이전 기사를 읽어보세요.>>深入解析Java中的位运算符:<<、>>和>>>

  • if (newCapacity - minCapacity < 0)

계산된 새 용량이 최소 용량 요구 사항을 충족하는지 확인하세요. 만족하지 않는 경우 새 용량은 최소 용량 minCapacity로 설정됩니다.

  • if (newCapacity - MAX_ARRAY_SIZE > 0)

새 용량이 최대 어레이 용량 제한을 초과하는지 확인하십시오. MAX_ARRAY_SIZE는 ArrayList 내부에 정의된 상수로, 배열의 최대 용량을 나타냅니다. 새 용량이 이 제한을 초과하는 경우 hugeCapacity(minCapacity) 메서드를 호출하여 충분히 큰 용량을 확보하세요.

_20230828230251.png

_20230828230304.png

  • elementData = Arrays.copyOf(elementData, newCapacity);

Arrays.copyOf() 메소드를 사용하여 원래 elementData 배열을 새 배열로 복사합니다. 새 배열의 용량은 계산된 새 용량 newCapacity입니다. 이는 실제 배열 확장 작업을 구현합니다.

사용상의 주의사항 및 최적화

  • 초기 크기

ArrayList를 생성할 때 대략적인 데이터 양을 예측할 수 있다면 적절한 초기 크기를 초기화하면 확장 횟수가 줄어들어 성능이 향상될 수 있습니다.

  • 잦은 확장 방지

빈번한 확장은 큰 성능 오버헤드를 가져오므로 여러 확장 작업이 트리거되는 것을 방지하려면 루프에 요소를 여러 번 추가하지 마십시오.

요약하다

일반적으로 사용되는 데이터 구조인 ArrayList는 동적 확장 메커니즘을 지원하여 프로그래밍 작업에 큰 편의성을 제공합니다. 동적 확장 원리와 애플리케이션 시나리오에 대한 심층적인 이해는 직장에서 ArrayList를 더 잘 사용하는 데 도움이 되며 인터뷰에서 탄탄한 기본 지식을 입증할 수도 있습니다.

불확실한 양의 데이터로 비즈니스 로직을 처리하든, 기술 인터뷰에서 ArrayList와 관련된 질문에 답하든, 동적 확장 메커니즘을 이해하면 다양한 문제를 보다 침착하게 처리할 수 있습니다.

추천

출처blog.csdn.net/weixin_44002151/article/details/132550370