velog에서 이전한 글 입니다.
ArrayList
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
private Object[] grow() {
return grow(size + 1);
}
private Object[] grow(int minCapacity) {
int oldCapacity = elementData.length;
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
oldCapacity >> 1 /* preferred growth */);
return elementData = Arrays.copyOf(elementData, newCapacity);
} else {
return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
}
}
private static final int DEFAULT_CAPACITY = 10;
ArrayList는 Vector, LinkedList는 list라 하자.new ArrayList<>();
로 벡터를 생성하면 elementData에 빈 obejct를 할당한다.
최초 add가 들어오면 if (s == elementData.length)
해당 분기에 걸리고 grow()가 실행된다.grow(int minCapacity)
에서 else 분기가 동작되고 elementData는 DEFAULT_CAPACITY 값인 10의 크기의 배열이 만들어진다.
10의 크기를 다 채운다음의 add를 보자.
grow의 if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
해당 분기에 걸리며 newCapacity
크기로 배열을 만들고 복사한다.
(ArraysSupport.newLength)
public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
// preconditions not checked because of inlining
// assert oldLength >= 0
// assert minGrowth > 0
int prefLength = oldLength + Math.max(minGrowth, prefGrowth); // might overflow
if (0 < prefLength && prefLength <= SOFT_MAX_ARRAY_LENGTH) {
return prefLength;
} else {
// put code cold in a separate method
return hugeLength(oldLength, minGrowth);
}
}
public static final int SOFT_MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8;
SOFT_MAX..
는 정수의 상한치에 근접한다. prefLength가 상한치에 거의 도달했거나 넘으면 else 분기가 동작한다.
일단 if분기의 경우를 살펴보자. 10의 크기를 채우고 add가 들어온다면 다음과 같다. ArraysSupport.newLength(10, 1, 10 >> 1)
10>>1 = 5
15>>1 = 7
22>>1 = 11
오른쪽 한칸 시프트 연산의 경우 원래 값의 반 정도되는 값이 나오는 것을 볼 수 있다.
그래서 if 분기의 return은 대략oldLength + Math.max(1, oldLength/2);
이렇게 볼 수 있다. 즉 원래 배열 크기의 1.5배 정도의 값이 newCapacity로 할당된다.
private static int hugeLength(int oldLength, int minGrowth) {
int minLength = oldLength + minGrowth;
if (minLength < 0) { // overflow
throw new OutOfMemoryError(
"Required array length " + oldLength + " + " + minGrowth + " is too large");
} else if (minLength <= SOFT_MAX_ARRAY_LENGTH) {
return SOFT_MAX_ARRAY_LENGTH;
} else {
return minLength;
}
}
oldLength + prefGrowth는 overflow이므로 oldLength + minGrowth(==1)로 시작한다. minGrowth를 더한 값마저 overflow라면 OutOfMemoryError
를 던진다.
overflow가 아니고 Integer.MAX_VALUE - 8 보다 같거나 작다면 최대 capacity로 할당하고 그 보다는 크다면 1씩 증가한 capacity인 minLength를 할당한다.
추가로 시간을 비교해보고 각 자료구조의 특성을 생각해보자.
2023.07.13 - [java] - 자바) ArrayList LinkedList 시간 비교 (23-07-06)
'Language > Java' 카테고리의 다른 글
java object equals (0) | 2023.08.08 |
---|---|
자바) ArrayList LinkedList 시간 비교 (23-07-06) (0) | 2023.07.13 |
자바) combination/ stream (23-06-19) (0) | 2023.07.13 |
자바) 와일드카드 (23-05-30) (0) | 2023.07.13 |
자바) List (23-05-26) (0) | 2023.07.13 |