본문 바로가기
Spring

[5] 자바 중급 문법 - ArrayList

by 민지기il 2025. 3. 28.

[1] ArrayList - 배열리스트 ( List 자료 구조를 사용하는데, 내부의 데이터는 Array에 보관하는 것)

1) 특정 배열의 위치에 숫자 추가하기

배열의 크기는 배열을 생성하는 시점에 미리 정해져야 한다.

public class ArrayMain {
    public static void main(String[] args) {
        int[] arr = new int[5];
        arr[0]=1;
        arr[1]=2;
        int index = 2;
        int newValue = 3;
        addAtIndex(arr, index, newValue);
    }
    public static void addAtIndex(int[] arr, int index, int newValue){
        for(int i=arr.length-1; i>index; i--){
            arr[i]=arr[i-1];
        }
        arr[index] = newValue;
    }
}

2) List

: 순서가 있고, 중복을 허용하는 자료 구조로 크기가 동적으로 변할 수 있다.

list의 크기: 실제 데이터가 입력된 크기, size

배열의 크기: 전체 데이터가 들어갈 수 있는 크기, capacity

list.set(2, "z"): list[2]에 z를 넣는다

> 크기 증가

public class MyArray {
    private Object[] elementData;
    private int size = 0;
    public void add(Object e){
        if(size == elementData.length){
            grow();
        }
        elementData[size] = 0;
        size++;
    }
    private void grow(){
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity*2;
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
}

Arrays.copyOf(기존배열, 새로운 길이): 새로운 길이로 배열을 생성하고, 기존 배열의 값을 새로운 배열에 복사한다.

 

3) 기능 추가

앞선 add는 기존의 데이터를 이동하지 않고 리스트의 마지막에 데이터를 추가한다. 

add(index, 데이터): index 위치에 데이터를 추가한다.

remove(index): index 위치의 데이터를 삭제한다.

   public void add2(int index, Object e){
        if(size == elementData.length){
            grow();
        }
        shiftRightFrom(index);
        elementData[index] = e;
        size++;
    }
    public Object remove(int index){
        Object oldValue = get(index);
        shiftLeftFrom(index);
        size--;
        elementData[size] = null;
        return oldValue;
    }
    //요소의 마지막부터 index까지 오른쪽으로 밀기
    private void shiftRightFrom(int index){
        for(int i=size; i>index; i--){
            elementData[i] = elementData[i-1];
        }
    }
    private void shiftLeftFrom(int index){
        for(int i=index ; i<size-1; i++){
            elementData[i] = elementData[i+1];
        }
    }
    private void grow(){
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity*2;
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
    public Object get(int index){
        return elementData[index];
    }

4) 제네릭

public class MyArrayList <E>{
    private Object[] elementData;
    private int size = 0;
    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++;
    }
    public void shiftRightFrom(int index){
        for(int i=size; i>index; i--){
            elementData[i] = elementData[i-1];
        }
    }
    private void grow() {
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity * 2;
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
}

E: Element의 줄임말임

public class ArrayListMain {
    public static void main(String[] args) {
        MyArrayList<String> stringList = new MyArrayList<>();
        stringList.add("a");
        MyArrayList<Integer> intList = new MyArrayList<>();
        intList.add(1);
    }
}

이제 stringList에는 String문자열만 보관하고 조회하고, intList에는 Integer숫자만 보관하고 조회할 수 있다.

다른 타입의 값을 저장하면 컴파일 오류가 발생한다.

이를 통해 추가로 값을 조회할 때도 위험한 다운 캐스팅 없이 지정한 타입으로 안전하게 조회할 수 있다.

제네릭을 사용한 덕분에 타입 인자로 지정한 타입으로만 안전하게 데이터를 저장하고, 조회할 수 있게 되었다

> Object 배열을 사용한 이유

상단의 코드에서 Object[] elementData를 그대로 사용했다.

제네릭은 런타임에 이레이저에 의해 타입 정보가 사라진다. 따라서 런타임에 타입 정보가 필요한 생성자에 사용할 수 없다. 

new E[DEFAULT_CAPACITY]는 불가하므로 new Object[DEFAULT_CAPACITY] 이렇게 해야한다.

> 제네릭 타입 인자

Object[] elementData;
void add(E e){
	elementData[size] = e;
}
E get(int index){
	return (E) elementData[index];
}

elementData[]에 데이터를 보관하는 add에는 E 타입으로 데이터를 입력한다.

elementData는 Object[]니까, 꺼낸 데이터는 Object로 나오고, String으로 쓰고 싶으니까 강제로 변환하는 다운캐스팅이 필요함

get()에는 보관할 때와 같은 E 타입으로 다운 캐스팅해서 반환한다. 

public class MyArrayList<E> {
    E[] elementData;
    void add(E e) { ... }
    E get(int index) { return elementData[index]; }
}

저장도 E 타입, 꺼낼 때도 E 타입이므로 더 이상 (String) 같은 다운캐스팅이 필요 없음!

'Spring' 카테고리의 다른 글

[7] 자바 고급 문법 - 문자  (0) 2025.03.28
[6] 자바 중급 문법 - List  (0) 2025.03.28
[4] 자바 중급 문법 - Generic  (0) 2025.03.26
[3] 자바 중급 문법 3 -- 날짜와 시간  (0) 2025.03.21
[2] 자바 중급 문법 2  (0) 2025.03.21