- 배열의 불편함을 해소하고 동적으로 데이터를 추가할 수 있는 자료구조를 List라고 함
- 배열 : 순서가 있고 중복을 허용하지만 크기가 정적으로 고정됨
- 리스트 : 순서가 있고 중복을 허용하지만 크기가 동적으로 변할 수 있음
package collection.array;
import java.util.Arrays;
public class MyArrayListV1 {
private static final int DEFAULT_CAPACITY = 5;
private Object[] elementData;
private int size = 0;
public MyArrayListV1() {
elementData = new Object[DEFAULT_CAPACITY];
}
public MyArrayListV1(int initialCapacity) {
elementData = new Object[initialCapacity];
}
public int size() {
return size;
}
public void add(Object e) {
elementData[size] = e;
size++;
}
public Object get(int index) {
return elementData[index];
}
public Object set(int index, Object element) {
Object oldValue = get(index);
elementData[index] = element;
return oldValue;
}
public int indexOf(Object o) {
for (int i = 0; i < size; i++) {
if (o.equals(elementData[i])) {
return i;
}
}
return -1;
}
@Override
public String toString() {
return Arrays.toString(Arrays.copyOf(elementData, size)) + " size=" +
size + ", capacity=" + elementData.length;
}
}
Object[] elementData : 다양한 타입의 데이터를 보관하기 위해 Object 배열을 사용함DEFAULT_CAPACITY : 리스트(MyArrayListV1)를 생성할 때 사용하는 기본 배열의 크기MyArryListV1(int initialCapacity) 생성자를 사용하면 됨size : 리스트 크기capacity와 다름size는 0이 됨add(Object e) : 리스트에 데이터를 추가함get(index) : 인덱스에 있는 항목 조회set(index, element) : 인덱스에 있는 항목 변경indexOf(Ojbect o) : 검색 기능-1을 반환함Arrys.copyOf(elementData, size) : size 크기의 배열을 새로 만듦toString() 출력시 size 이후의 의미없는 값을 출력하지 않기 위해 사용함package collection.array;
public class MyArrayListV1Main {
public static void main(String[] args) {
MyArrayListV1 list = new MyArrayListV1();
System.out.println("==데이터 추가==");
System.out.println(list);
list.add("a");
System.out.println(list);
list.add("b");
System.out.println(list);
list.add("c");
System.out.println(list);
System.out.println("==기능 사용==");
System.out.println("list.size(): " + list.size());
System.out.println("list.get(1): " + list.get(1));
System.out.println("list.indexOf('c'): " + list.indexOf("c"));
System.out.println("list.set(2, 'z'), oldValue: " + list.set(2, "z"));
System.out.println(list);
System.out.println("==범위 초과==");
list.add("d");
System.out.println(list);
list.add("e");
System.out.println(list);
//범위 초과, capacity가 늘어나지 않으면 예외 발생
list.add("f");
System.out.println(list);
}
}
실행결과
==데이터 추가==
[] size=0, capacity=5
[a] size=1, capacity=5
[a, b] size=2, capacity=5
[a, b, c] size=3, capacity=5
==기능 사용==
list.size(): 3
list.get(1): b
list.indexOf('c'): 2
list.set(2, 'z'), oldValue: c
[a, b, z] size=3, capacity=5
==범위 초과==
[a, b, z, d] size=4, capacity=5
[a, b, z, d, e] size=5, capacity=5
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out
of bounds for length 5
at collection.array.MyArrayListV1.add(MyArrayListV1.java:25)
at collection.array.MyArrayListV1Main.main(MyArrayListV1Main.java:30)

list.add("a")[a] size=1, capacity=5
size가 배열의 크기인 capacity에 도달하면 더는 데이터를 추가할 수 없음
따라서 f값을 입력할 때 예외가 발생함
동적으로 저장할 수 있는 크기가 커지는 상황은 아니기 때문에, 데이터의 크기가 동적으로 변할 수 있도록 코드를 변경해야함
```java
package collection.array;
import java.util.Arrays;
public class MyArrayListV2 {
private static final int DEFAULT_CAPACITY = 5;
private Object[] elementData;
private int size = 0;
public MyArrayListV2() {
elementData = new Object[DEFAULT_CAPACITY];
}
public MyArrayListV2(int initialCapacity) {
elementData = new Object[initialCapacity];
}
public int size() {
return size;
}
public void add(Object e) {
//코드 추가
if (size == elementData.length) {
grow();
}
elementData[size] = e;
size++;
}
//코드 추가
private void grow() {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity * 2;
elementData = Arrays.copyOf(elementData, newCapacity);
}
public Object get(int index) {
return elementData[index];
}
public Object set(int index, Object element) {
Object oldValue = get(index);
elementData[index] = element;
return oldValue;
}
public int indexOf(Object o) {
for (int i = 0; i < size; i++) {
if (o.equals(elementData[i])) {
return i;
}
}
return -1;
}
@Override
public String toString() {
return Arrays.toString(Arrays.copyOf(elementData, size)) + " size=" +
size + ", capacity=" + elementData.length;
}
}
추가된 부분은 grow() 메서드와 이 메서드를 호출하는 add() 메서드
add() 메서드에서 데이터를 추가할 때 size가 배열의 크기에 도달했다면 더는 데이터를 추가할 수 없음
따라서 이때는 grow()를 호출해서 기존 배열을 복사한 새로운 배열을 만들고 배열의 크기도 여유있게 2배로 늘려줌
Arrays.copyOf(기존배열, 새로운 길이) : 새로운 길이로 배열을 생성하고 기존 배열의 값을 새로운 배열에 복사함package collection.array;
public class MyArrayListV2Main {
public static void main(String[] args) {
MyArrayListV2 list = new MyArrayListV2(2);
System.out.println(list);
list.add("a");
System.out.println(list);
list.add("b");
System.out.println(list);
list.add("c");
System.out.println(list);
list.add("d");
System.out.println(list);
list.add("e");
System.out.println(list);
list.add("f");
System.out.println(list);
}
}
실행결과
[] size=0, capacity=2
[a] size=1, capacity=2
[a, b] size=2, capacity=2
[a, b, c] size=3, capacity=4
[a, b, c, d] size=4, capacity=4
[a, b, c, d, e] size=5, capacity=8
[a, b, c, d, e, f] size=6, capacity=8
배열의 크기를 초과할 때

size가 배열의 크기인 capacity를 초과하게 됨grow() 메서드를 호출하는데, 이 메서드는 다음과 같은 역할을 수행함Arrays.copyOf(기존배열, 새로운길이)를 사용해서 2배 큰 배열을 새로 생성하면서 동시에 새로운 배열에 기존 배열의 값을 복사함
elementData는 기존보다 2배 큰 capacity를 가진 배열을 보유하게 됨x001)은 더는 참고하는 곳이 없으므로 GC의 대상이 됨grow()를 호출할 때 배열의 크기는 기존과 비교해서 2배씩 증가함
예) 2-> 4-> 8 -> 16 -> 32 -> 64 -> 128
데이터가 하나 추가될 때마다 배열의 크기를 1씩만 증가하게 되면 배열의 복사하는 연산이 너무 자주 발생할 가능성이 높음
배열을 새로 복사해서 만드는 연산은 배열을 새로 만들고 또 기존 데이터를 복사하는 시간이 걸리므로 가능한 줄이는 것이 좋음
참고로 예제0를 단순히 하기 위해 여기서는 2배씩 증가를 했지만, 보통 50% 정도 증가하는 방법을 사용함
MyArrayListV2는 정적인 배열과 다르게 크기가 동적으로 변하는 자료구조MyArrayListV2 내부에서는 배열을 사용하지만, MyArrayListV2를 사용하는 개발자는 이런 부분을 신경쓰지 않아도 됨