Tistory ๋ธ๋ก๊ทธ ํฌ์คํ ๋ฐ๋ก๊ฐ๊ธฐ
Java๋ก ๊ฐ๋ฐํ๋ฉด์ ๋ฐฐ์ด์ ์ฌ์ฉํด์ผ ํ๋ ๊ฒฝ์ฐ Collection ํ๋ ์์ํฌ์ ArrayList ํด๋์ค๋ฅผ ์ฌ์ฉํ ์ผ์ด ๊ต์ฅํ ๋ง์ต๋๋ค.
๋ฐฐ์ด์ ๊ณ ์ ๊ธธ์ด ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ผ์ ์ต์ด์ ํ ๋นํด๋์ ๊ธธ์ด๋ฅผ ๋์ด๊ฐ๋ฉด ์ง์ ๋ ํฐ ํฌ๊ธฐ์ ์๋ก์ด ๋ฐฐ์ด์ ๋ง๋ค์ด์ค์ผ ํ๋ ๋ถํธํจ์ด ์๋ ๋ฐ๋ฉด, ArrayList๋ ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํ ๋ ๋ด๋ถ์ ์ผ๋ก ๊ธธ์ด๋ฅผ ๊ฐ๋ณ์ ์ผ๋ก ๊ด๋ฆฌํด์ฃผ๊ธฐ ๋๋ฌธ์ ๋ ํธ๋ฆฌํ๊ฒ ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์ด์ฃ .
๊ทธ๋ ๋ค๋ฉด ์ค์ ๋ก ๋ด๋ถ์์ ์ด๋ค์์ผ๋ก ArrayList์ ๊ธธ์ด๋ฅผ ๊ฐ๋ณ์ ์ผ๋ก ๊ด๋ฆฌํ ๊น์?
์ด๋ฐ ArrayList ํด๋์ค๋ ๊ฐ๋ฐ์๋ค์ด ์์ฑํ ์ฝ๋์ด๊ณ , JDK ๋ฒ์ ์ด ์ ๋๋ฉด์ ๊ธฐ์กด ๊ตฌํ ์ฝ๋์ ๋ฌธ์ ์ ์ ๋ณด์ํ๊ฑฐ๋ ๋ ํจ์จ์ด ์ข๊ฒ๋ ์ ๋ฐ์ดํธํฉ๋๋ค.
๊ทธ๋์ JDK 6,7,8 ๋ฒ์ ๊ฐ ArrayList ๊ตฌํ ๋ฐฉ์์ ์ด๋ค ์ฐจ์ด๊ฐ ์๋์ง ์์๋ดค์ต๋๋ค.
(์๋ JDK ๋ฒ์ ๋ณ ์ฝ๋๋ ์๋ชป๋ ์ดํด๋ฅผ ๋ฐฉ์งํ๊ณ ์ ์ค์ JDK ์์ค์ฝ๋๋ฅผ ๊ทธ๋๋ ์ฒจ๋ถํ์ผ๋ ์ฐธ๊ณ ๋ฐ๋๋๋ค.)
/**
* Increases the capacity of this <tt>ArrayList</tt> instance, if
* necessary, to ensure that it can hold at least the number of elements
* specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
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);
}
}
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacity(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
/**
* Inserts the specified element at the specified position in this
* list. Shifts the element currently at that position (if any) and
* any subsequent elements to the right (adds one to their indices).
*
* @param index index at which the specified element is to be inserted
* @param element element to be inserted
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacity(size+1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}add ๋ฉ์๋์ ๋ด์ฉ์ ensureCapacity๊ฐ ArrayList์ ํ์ฅ ์ฌ๋ถ๋ฅผ ํ์ธํ๊ณ ์์
ํ๋ ๋ถ๋ถ์ด๊ธฐ ๋๋ฌธ์ ํ๋ฒ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
oldCapacity์ ๊ธฐ์กดelementData์ ๊ธธ์ด ํ ๋น- ์ต์ ํ์ ๊ธธ์ด
minCapacity๊ฐoldCapactiy๋ณด๋ค ํฐ ๊ฒฝ์ฐnewCapacity๋ฅผoldCapacity์ 3์ ๊ณฑํ ๋ค 2๋ก ๋๋ ๋ค์ 1์ ๋ํ ๊ฐ(์ฝ 1.5๋ฐฐ)์ผ๋ก ์ก๋๋ค.- ๋ง์ฝ ์๋ก์ด
newCapacity๋minCapacity๋ณด๋ค ์๋ค๋ฉดnewCapacity๋ฅผminCapacity๋ก ์นํํ๋ค. Arrays.copyOf()๋ฅผ ์ด์ฉํด์ ๊ธฐ์กดelementData๋ฅผnewCapacity๋งํผ ๋ณต์ฌํ๋ค.
- 2๋ฒ์ ๊ฒฝ์ฐ๊ฐ ์๋๋ผ๋ฉด ์๋ฌด ์์ ์ ์ํด๋ ๋๊ธฐ ๋๋ฌธ์ ํจ์ ์ข ๋ฃ.
JDK 6์์๋ ๋ ํฐ ArrayList๊ฐ ํ์ํ ๊ฒฝ์ฐ ๊ณฑ์ ๊ณผ ๋๋์ ์ฐ์ฐ์ ํตํด ๊ธฐ์กด ๊ธธ์ด์์ ์ฝ 1.5๋ฐฐ๋งํผ์ ํฌ๊ธฐ๋ก ํ์ฅํ ์๋ก์ด ๊ธธ์ด์ ArrayList๋ฅผ ์์ฑํ์ฌ ์ฌ์ฉํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
/**
* Inserts the specified element at the specified position in this
* list. Shifts the element currently at that position (if any) and
* any subsequent elements to the right (adds one to their indices).
*
* @param index index at which the specified element is to be inserted
* @param element element to be inserted
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
/**
* Increases the capacity of this <tt>ArrayList</tt> instance, if
* necessary, to ensure that it can hold at least the number of elements
* specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
public void ensureCapacity(int minCapacity) {
if (minCapacity > 0)
ensureCapacityInternal(minCapacity);
}
private void ensureCapacityInternal(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
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);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}add ๋ฉ์๋์ ๋ด์ฉ์ ensureCapacityInternal๋ฅผ ๋ณด๋ฉด modCount๋ฅผ ๋๋ ค์ค ๋ค grow ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์ด grow ๋ฉ์๋๊ฐ ArrayList์ ํ์ฅ ์ฌ๋ถ๋ฅผ ํ์ธํ๊ณ ์์
ํ๋ ๋ถ๋ถ์ด๊ธฐ ๋๋ฌธ์ ํ๋ฒ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
oldCapacity์ ๊ธฐ์กดelementData์ ๊ธธ์ด ํ ๋น- ์ต์ ํ์ ๊ธธ์ด
minCapacity๊ฐoldCapactiy๋ณด๋ค ํฐ ๊ฒฝ์ฐnewCapacity๋ฅผoldCapacity์oldCapacity๋ฅผ ๋นํธ์ฐ์ฐ์ ํตํด ์ค๋ฅธ์ชฝ์ผ๋ก ํ์นธ shiftํ ๊ฐ์ ๋ํ ๋ค ์ ์ฅํ๋ค.- ๋ง์ฐฌ๊ฐ์ง๋ก ๋ง์ฝ ์๋ก์ด
newCapacity๋minCapacity๋ณด๋ค ์๋ค๋ฉดnewCapacity๋ฅผminCapacity๋ก ์นํํ๋ค. - ๋ง์ฝ,
newCapacity๊ฐMAX_ARRAY_SIZE๋ณด๋ค ํฌ๋ค๋ฉดhugeCapacity(minCapacity)๋ฅผ ํธ์ถํ๋ค.hugeCapacity๋ฅผ ํตํด overflow์ธ ๊ฒฝ์ฐOutOfMemoryError๋ฅผ ๋์ง๊ณ , overflow๊ฐ ์๋ ๊ฒฝ์ฐ์๋minCapacity์ ๊ฐ์ ๋ฐ๋ผMAX_ARRAY_SIZEํน์Integer.MAX_VALUE๋ก ์ง์ ํ๋ค.
Arrays.copyOf()๋ฅผ ์ด์ฉํด์ ๊ธฐ์กดelementData๋ฅผnewCapacity๋งํผ ๋ณต์ฌํ๋ค.
JDK 7์์๋ JDK 6์ ๋ค๋ฅด๊ฒ ๋ ํฐ ArrayList๊ฐ ํ์ํ ๊ฒฝ์ฐ ๊ณฑ์ ๊ณผ ๋๋์ ์ฐ์ฐ์ ํตํ์ง ์๊ณ , ๋ ๋น ๋ฅด๊ณ ํจ์จ์ ์ธ ๋นํธ์ฐ์ฐ์ ํ์ฉํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
oldCapacity + (oldCapacity >> 1)์ ๋นํธ์ฐ์ฐ ๋ถ๋ถ์ ์ดํด๋ณด๋ฉด, oldCapacity์ 2์ง์๋ฅผ ์ค๋ฅธ์ชฝ์ผ๋ก 1๋งํผ shift ํ์ฌ 2^1๋งํผ ๋๋๋ ๊ฒ๊ณผ ๋์ผํ ์ฐ์ฐ์ ์ํํ์ฌ ๊ธฐ์กด ๊ธธ์ด์์ ์ฝ 1.5๋ฐฐ๋งํผ์ ํฌ๊ธฐ๋ก ํ์ฅํ ์๋ก์ด ArrayList๋ฅผ ์์ฑํ๋ ๊ฒ์ด์ฃ .
์ถ๊ฐ๋ก, overflow์ ๋ํ exception handling์ด ์ถ๊ฐ๋ ๊ฒ๋ JDK 6์์ ์ฐจ์ด์ ์ ๋๋ค.
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
/**
* Inserts the specified element at the specified position in this
* list. Shifts the element currently at that position (if any) and
* any subsequent elements to the right (adds one to their indices).
*
* @param index index at which the specified element is to be inserted
* @param element element to be inserted
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
/**
* Increases the capacity of this <tt>ArrayList</tt> instance, if
* necessary, to ensure that it can hold at least the number of elements
* specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != EMPTY_ELEMENTDATA)
// any size if real element table
? 0
// larger than default for empty table. It's already supposed to be
// at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
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);
}JDK 8์ JDK 7๊ณผ ๋์ผํ๊ฒ ๋นํธ์ฐ์ฐ์ ํตํด ์ฌ์ด์ฆ๊ฐ ๋ ํฐ ArrayList๋ฅผ ๋ง๋ค์ด์ค๋๋ค.
JDK 7๊ณผ์ ์ฐจ์ด๋ elementData๊ฐ ArrayList ์ธ์คํด์ค ์ต์ด ์์ฑ ์ ํ ๋น๋๋ EMPTY_ELEMENTDATA์ธ ๊ฒฝ์ฐ, ์ธ์๋ก ๋ฐ์ minCapacity์ DEFAULT_CAPACITY์ ๊ฐ์ธ 10 ์ค ๋ ํฐ ์๋ฅผ minCapacity์ ํ ๋นํ๋ ๋ถ๋ถ์ด ์ถ๊ฐ๋ ์ ์
๋๋ค.
์ด๋ฒ ๊ธฐํ๋ก ์ ๋ง ๋ง์ด ์ฌ์ฉํ๋ ArrayList์ ๊ธธ์ด๋ฅผ ์ด๋ป๊ฒ ๊ฐ๋ณ์ ์ผ๋ก ๊ด๋ฆฌํ๋์ง ์์ธํ๊ณ ์ดํด๋ณด์๊ณ , JDK ๋ฒ์ ๋ณ ์๋ก ์ถ๊ฐ๋ ๋ด์ฉ๋ค ์ธ์๋ ๊ธฐ์กด์ ์ด๋ฏธ ์๋ ํด๋์ค๋ค์ ์ด๋ค ์์ ๋ค์ ํ๋์ง ์๊ฒ ๋์์ต๋๋ค.
๋นํธ์ฐ์ฐ์ ๋ํด๋ ์๊ณ ์์์ง๋ง ์ด๋ ๊ฒ ์ค์ ๋ก ํ์ฉ์ด ๋ ๋ถ๋ถ์ ์ฒ์ ๋ณด์๋๋ฐ, ์ด ์ญ์ ์ด๋ก ์ผ๋ก๋ง ๋ฐฐ์ ๋ ๋ด์ฉ์ ์ค์ ์ฌ๋ก๋ก ๋ณด๊ณ ๊ทธ ํจ์จ์ฑ์ ํ์ธํ ์ ์๋ ์ข์ ๊ธฐํ์๋ ๊ฒ ๊ฐ์ต๋๋ค.
ํนํ, ๋ด๋ถ ์์ค์ฝ๋๋ ์ดํดํ๊ธฐ ์ด๋ ต๋ค๋ ๋๋ ค์์ด ์์๋๋ฐ ์ด์ด์ ํ์ธํด๋ณด๋ ์ค์ ๋ก ๊ทธ๋ ์ง๋ ์์ ์์ผ๋ก ํญ์ ์ด๋ฐ ์์ผ๋ก ๊น์ด ๊ณต๋ถํ๋ ๋ฒ๋ฆ์ ๋ค์ผ ์๊ฐ์ ๋๋ค.