JAVA

Java 버전 별 ArrayList add 동작

devchive 2023. 9. 6. 18:51

Java 6

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

Java 6 에서 ArrayList add이다. ensureCapacity에 현재 size +1을 전달하여 크기를 확인한다.

public void ensureCapacity(int minCapacity) {
	modCount++;
	int oldCapacity = elementData.length;
	if (minCapacity > oldCapacity) {
	    Object oldData[] = elementData;
	    int newCapacity = (oldCapacity * 3)/2 + 1;
    	    if (newCapacity < minCapacity)
		newCapacity = minCapacity;
            // minCapacity is usually close to size, so this is a win:
            elementData = Arrays.copyOf(elementData, newCapacity);
	}
}

ensureCapacity에서 기존 list의 크기와 비교해서 크기가 늘어야 한다면 기존 크기에 *3 / 2 +1하여 새로운 사이즈를 만들고 크기를 정하여 배열을 복사해준다.

 

Java 7

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

Java7에서의 add이다. ensureCapacityInternal로 크기를 확인해준다.

    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

데이터가 초기 빈 값이라면 DEFAULT_CAPACITY인 10과 비교하여 큰 값을 capacity로 설정하여 ensuerExplicitCapacity에 넘겨준다.

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

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

이렇게 넘어온 minCapacity가 현재 list 길이보다 크면 grow 를 실행한다.

    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);
    }

Java7에서는 Java 6과 다르게 비트 연산으로 새로운 capacity를 계산한다. 만약 계산된 capacity가 MAX_ARRAY_SIZE (Java 7에서는 Integer.MAX_VALUE - 8) 보다 크다면 hugeCapacity를 호출한다.

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

만약 이렇게 넘어온 capacity가 overflow 되어서 음수가 되었다면 에러를 발생시킨다. 그게 아니라면 최대 Integer.MAX_VALUE 크기를 반환한다.

 

Java 8

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

Java 8에서의 add이다. Java 7 과 마찬가지로 ensuerCapacityInternal을 호출해준다.

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

ensuerCapacityInternal 이다. Java 7 과 달라진점은 Java 7 에서는 encusrCapacityInternal 에서 계산하던 작업을 별도로 calculateCapacity로 분리해서 작업한다. 또 기존 Java 7 에서의 EMPTY_ELEMANTDATA 가 아니라 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 로 바뀌었다. 이건 초기값 없이 ArrayList를 초기화하면 기본적으로 갖게되는 값이다. 이 경우 기본적인 초기 사이즈는 10을 갖게 된다.
Java 8에서는 Java 7과는 다르게 빈 elementData와 초기 elementData를 분리해서 관리하고있다.