
'김영한의 실전 자바 - 중급 2편' 강의를 들으면서 복습할만한 내용을 정리하였다.
배열과 같이 여러 데이터(자료)를 구조화해서 다루는 것을 자료 구조라한다.
자바는 배열 뿐만 아니라, 컬렉션 프레임워크라는 이름으로 다양한 자료 구조를 제공한다.
배열의 특징

O(1))배열 index 사용 예시

arr[2] 에 위치한 자료를 찾는다고 가정해보자.int 는 4byte 를 차지한다.간단 정리
공식: 배열의 시작 참조 + (자료의 크기 * 인덱스 위치)
배열의 검색
배열에 들어있는 데이터를 찾는 것을 검색이라 한다.
배열에 들어있는 데이터를 검색할 때는 배열에 들어있는 데이터를 하나하나 비교해야 한다. 배열의 크기가 n이면 연산도 n만큼 필요하다.(O(n))
배열 정리
O(1)O(n)배열의 특정 위치에 데이터를 추가하려면 기존 데이터가 오른쪽으로 한 칸씩 이동해야 한다. 새로운 데이터를 입력할 공간을 확보해야 하는 것이다. (O(n))
배열은 가장 기본적인 자료 구조이고, 특히 인덱스를 사용할 때 최고의 효율이 나온다. 하지만 이런 배열에는 큰 단점이 있다. 바로 배열의 크기를 배열을 생성하는 시점에 미리 정해야 한다는 점이다.
배열의 불편함
이런 불편함을 해소하고 동적으로 데이터를 추가할 수 있는 자료구조를 List(리스트)라 한다.
public class MyArrayListV4<E> {
private static final int DEFAULT_CAPACITY = 5;
private Object[] elementData;
private int size = 0;
public MyArrayListV4() {
elementData = new Object[DEFAULT_CAPACITY];
}
public MyArrayListV4(int initialCapacity) {
elementData = new Object[initialCapacity];
}
public int size() {
return size;
}
public void add(E e) {
if (size == elementData.length) {
grow();
}
elementData[size] = e;
size++;
}
public void add(int index, E e) {
if (size == elementData.length) {
grow();
}
//데이터 이동
shiftRightFrom(index);
elementData[index] = e;
size++;
}
private void shiftRightFrom(int index) {
for (int i = size; i > index; i--) {
elementData[i] = elementData[i - 1];
}
}
private void grow() {
elementData = Arrays.copyOf(elementData, elementData.length * 2);
}
@SuppressWarnings("unchecked")
public E get(int index) {
return (E) elementData[index];
}
public E set(int index, E e) {
E o = get(index);
elementData[index] = e;
return o;
}
public E remove(int index) {
E oldValue = get(index);
shiftLeftFrom(index);
size--;
elementData[size] = null;
return oldValue;
}
private void shiftLeftFrom(int index) {
for (int i = index; i < size - 1; i++) {
elementData[i] = elementData[i + 1];
}
}
public int indexOf(E e) {
for (int i = 0; i < size; i++) {
if (elementData[i].equals(e)) return i;
}
return -1;
}
public String toString() {
return Arrays.toString(Arrays.copyOf(elementData, size))
+ " size = " + size
+ ", capacity = " + elementData.length;
}
}
private static final int DEFAULT_CAPACITY = 5 : 먼저 배열의 초기 용량 값을 정한다.private Object[] elementData : 다양한 타입의 데이터를 보관하기 위해 Object 배열을 사용한다.동적으로 배열의 크기를 늘리는 코드
public void add(E e) {
if (size == elementData.length) {
grow();
}
elementData[size] = e;
size++;
}
private void grow() {
elementData = Arrays.copyOf(elementData, elementData.length * 2);
}
add() 메서드에서 데이터를 추가할 때 size 가 배열의 크기에 도달했다면 더는 데이터를 추가할 수 없다.grow() 를 호출해서 기존 배열을 복사한 새로운 배열을 만들고 배열의 크기도 여유있게 2배로 늘려준다.Arrays.copyOf(기존배열, 새로운길이) : 새로운 길이로 배열을 생성하고, 기존 배열의 값을 새로운 배열에 복사한다.50% 정도 증가하는 방법을 사용한다.index 위치에 데이터를 추가/제거하는 코드
데이터 추가
public void add(int index, E e) {
if (size == elementData.length) {
grow();
}
//데이터 이동
shiftRightFrom(index);
elementData[index] = e;
size++;
}
private void shiftRightFrom(int index) {
for (int i = size; i > index; i--) {
elementData[i] = elementData[i - 1];
}
}
index 위치에 데이터를 추가하려면 기존에 index 부터 배열의 끝까지 존재하던 데이터를 한칸씩 오른쪽으로 밀어주고 index 에 데이터를 추가한다.데이터 삭제
public E remove(int index) {
E oldValue = get(index);
shiftLeftFrom(index);
size--;
elementData[size] = null;
return oldValue;
}
private void shiftLeftFrom(int index) {
for (int i = index; i < size - 1; i++) {
elementData[i] = elementData[i + 1];
}
}
index 위치의 데이터를 삭제하려면 기존에 index 다음부터 배열의 끝까지 존재하던 데이터를 왼쪽으로 한칸씩 밀어주고 index 의 데이터를 삭제한다.제네릭을 도입하면 타입 안정성을 확보하면서 여러 데이터 타입을 섞어서 보관하여 다운 캐스팅시 예외가 발생하는 문제를 한번에 해결할 수 있다.
<E> 제네릭을 도입하여 문자열만 보관할 때는 문자열만 보관하고, 정수를 보관할 때는 정수만 보관할 수 있게 되서 값을 조회할 때 위험한 다운 캐스팅 없이 지정한 타입으로 안전하게 조회할 수 있다.
Object 배열을 사용한 이유
Object[] elementData 을 그대로 사용한 이유
new E[DEFAULT_CAPACITY]Object 를 그대로 사용해야 한다.new Object[DEFAULT_CAPACITY]정리하면 생성자에는 제네릭의 타입 매개변수를 사용할 수 없는 한계가 있다. 따라서 배열을 생성할 때 대안으로 Object 배열을 사용해야 한다. 하지만 제네릭이 리스트의 데이터를 입력 받고 반환하는 곳의 타입을 고정해준다. 따라서 고정된 타입으로 Object 배열에 데이터를 보관하고, 또 데이터를 꺼낼 때도 같은 고정된 타입으로 안전하게 다운 캐스팅 할 수 있다.
ArrayList의 단점
이러한 단점을 해결한 자료구조로는 링크드리스트(LinkedList)가 있다.