Java

[Java] 소스코드 탐험 - 2. ArrayList(feat. AbstractList)

디벨로펄 2023. 7. 23.
반응형

두번째로 볼 친구는 Iterator에 이은 ArrayList

ArrayList를 살펴보니 상당하다.

AbstractList를 상속하고 있으며, List<E>, RandomAccess, Cloneable, Serializable을 구현하고 있다. 

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

먼저 여기서 살펴볼건

1. ArrayList가 가변크기를 어떻게 유지하는지?

2. 어떻게 동시 수정을 판단하는지.

 

private static final int DEFAULT_CAPACITY = 10;
transient Object[] elementData;

* transient : 필드 중 직렬화하지 않을 것을 지정하기 위해 사용된다. = 직렬화 작업에서 제외된다.(Serializable)

- 민감한 정보를 직렬화 제외

- 객체가 계산해서 얻을 수 있는 값인 경우

- static, final과 함께 사용하면 효과가 없다.(static은 객체 고유의 값이 아니고, final은 객체값 초기화하기 때문)

 

ArrayList가 크기를 조정하는 방법

ArrayList도 내부에서는 객체를 배열로 관리한다.

크기를 넘어서는 add요청이 있을 때마다, 크기가 더 큰 배열을 생성하고 현재 배열 원소를 복사한다.

add, grow

    /**
     * List의 최소 허용량을 minCapacity로 키운다.
     * minCapacity가 0보다 작으면 OutOfMemoryError를 던진다.
     */
    private Object[] grow(int minCapacity) {
        int oldCapacity = elementData.length;
        if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        // 현재 빈 List가 아니면 늘려준다.
            int newCapacity = ArraysSupport.newLength(oldCapacity,
                    minCapacity - oldCapacity, /* minimum growth */
                    oldCapacity >> 1           /* preferred growth */);
            return elementData = Arrays.copyOf(elementData, newCapacity);
            // Arrays.copyOf까지 들어가보면, 새로운 배열 생성 후 기존 배열을 넣어준다.
        } else {
        // 빈 List면 새로 배열 생성해준다.
            return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
        }
    }
    
    private Object[] grow() {
        return grow(size + 1);
    }
    
    private void add(E e, Object[] elementData, int s) {
        // 배열의 사이즈가 현재 넣고자하는 INDEX보다 작다면. 배열 확장함
        if (s == elementData.length)
            elementData = grow(); 
        elementData[s] = e;
        size = s + 1;
    }

    public boolean add(E e) {
        modCount++;
        add(e, elementData, size);
        return true;
    }
동시 수정 판단 - modCount

 - 값변경이 있을 때마다 modCount값을 변경시킨다.

add, remove

A의 modCount가 expectedModCount와 일치하지 않는 경우 concurrentModification으로 판단하고 예외를 던진다.

    private void checkForComodification(final int expectedModCount) {
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }
반응형

댓글