본문 바로가기

Programming/Java

[Java] 김영한의 자바 중급 2편 #3 - ArrayList

반응형

0. 빅오(O) 표기법

빅오(Big O) 표기법은 알고리즘의 성능을 분석할 때 사용하는 수학적 표현 방식이다.

여기서 중요한 것은 알고리즘의 정확한 실행 시간을 계산하는 것이 아니라,

 

데이터 양의 증가에 따른 성능의 변화 추세를 이해하는 것이다.

 

 

빅오 표기법의 예시 O(1) - 상수 시간: 입력 데이터의 크기에 관계없이 알고리즘의 실행 시간이 일정한다.

O(n) - 선형 시간: 알고리즘의 실행 시간이 입력 데이터의 크기에 비례하여 증가한다.

O(n²) - 제곱 시간: 알고리즘의 실행 시간이 입력 데이터의 크기의 제곱에 비례하여 증가한다.

O(log n) - 로그 시간: 알고리즘의 실행 시간이 데이터 크기의 로그에 비례하여 증가한다.

O(n log n) - 선형 로그 시간

 

0.1. 빅오 표기법 정리

빅오 표기법은 매우 큰 데이터를 입력한다고 가정하고, 데이터 양 증가에 따른 성능의 변화 추세를 비교하는데 사용한다.

쉽게 이야기해서 정확한 성능을 측정하는 것이 목표가 아니라 매우 큰 데이터가 들어왔을 때의 대략적인 추세를 비교를 하는 것이 목적이다.

 

 

1. 배열의 특징1 - 배열과 인덱스

자료구조란?

여러 데이터(자료)를 구조화해서 다루는 것

package collection.array;

import java.util.Arrays;

public class ArrayMain1 {
    public static void main(String[] args) {
        int[] arr = new int[5];
        
        //index 입력: O(1)
        System.out.println("==index 입력: O(1)==");
        arr[0] = 1;
        arr[1] = 2;
        arr[2] = 3;
        System.out.println(Arrays.toString(arr));
        
        //index 변경: O(1)
        System.out.println("==index 변경: O(1)==");
        arr[2] = 10;
        System.out.println(Arrays.toString(arr));
        
        //index 조회: O(1)
        System.out.println("==index 조회: O(1)==");
        System.out.println("arr[2] = " + arr[2]);
        
        //검색: O(n)
        System.out.println("==배열 검색: O(n)==");
        System.out.println(Arrays.toString(arr));
        
        int value = 10;
        for (int i = 0; i < arr.length; i++) {
            
            System.out.println("arr[" + i + "]:" + arr[i]);
            
            if (arr[i] == value) {
                System.out.println(value + " 찾음");
                break;
            }
        }
    }
}

// 출력
==index 입력: O(1)==
[1, 2, 3, 0, 0]
==index 변경: O(1)==
[1, 2, 10, 0, 0]
==index 조회: O(1)==
arr[2] = 10
==배열 검색: O(n)==
[1, 2, 10, 0, 0]
arr[0]:1
arr[1]:2
arr[2]:10
10 찾음

 

 

1.1. 배열 메모리 그림

 

 

  • 배열에서 자료를 찾을 때 인덱스(index)를 사용하면 매우 빠르게 자료를 찾을 수 있다.
  • 인덱스를 통한 입력, 변경, 조회의 경우 1번의 계산으로 자료의 위치를 찾을 수 있다.

1.2. 배열에서의 검색

배열에 들어있는 특정 데이터를 찾는 행위를 검색이라고 한다.

배열에 들어있는 특정 데이터를 찾을 때는 for loop을 돌면서 데이터를 하나하나 비교해야 한다.

→ 따라서 평균적으로 볼 때 배열의 크기가 클 수록 오랜 시간이 걸린다.

→ 배열의 크기가 n이면 연산도 n만큼 필요하게 된다.


2. 배열의 특징2 - 데이터 추가

데이터를 추가하는 행위는 기존 데이터를 유지하면서 새로운 데이터를 입력한다는 것을 뜻한다.

(만약 여기서 데이터를 중간에 추가하면 기존 데이터가 오른쪽으로 한 칸씩 이동되어야 한다.)

2.1. 첫번째 위치에 데이터 추가 : O(n)

[기존]

 

 

[추가]

 

  • 기존 데이터들은 모두 오른쪽으로 한 칸씩 밀어서 추가할 위치를 확보한다.
    • 이 때, 배열의 마지막 부분부터 오른쪽으로 밀어야 데이터를 유지할 수 있다.
    • 왼쪽의 데이터를 오른쪽으로 대입하는 과정을 반복한다.

 

2.2. 배열의 중간 위치에 추가 : O(n)

[기존]

 

 

[추가]

 

 

  • 지정한 index에 데이터를 추가해야 하기 때문에 지정한 index를 확보해야 한다.
    • 따라서 index부터 시작해서 데이터들을 오른쪽으로 밀어야 한다.
    • 이 경우 지정한 index 기준 왼쪽의 데이터들은 이동하지 않아도 된다.

2.3. 배열의 마지막 위치에 추가 : O(1)

 

 

  • 이 경우 기존의 데이터를 이동하지 않아도 되며 단순하게 값만 입력하면 된다.

2.4. 코드로 구현해보기

package collection.array;

import java.util.Arrays;

public class ArrayMain2 {
    public static void main(String[] args) {
        // Q. int[]는 Wrapper class가 아니기 때문에 기본 method 밖에 없는건가?
        // A. 이것을 배열이라고 한다..? (Array)
        int[] arr = new int[5];
        arr[0] = 1;
        arr[1] = 2;

        System.out.println("배열의 첫번째 위치에 3 추가 o(n)");
        int newValue = 3;
        addFirst(arr, newValue);
        System.out.println(Arrays.toString(arr));

        System.out.println("배열의 특정 위치에 추가 o(n)");
        int newValue2 = 4;
        addAtIndex(arr, 3, newValue2);
        System.out.println(Arrays.toString(arr));

        System.out.println("배열의 마지막 위치에 추가 o(1)");
        int newValue3 = 5;
        addLast(arr, newValue3);
        System.out.println(Arrays.toString(arr));
    }

    private static void addFirst(int[] arr, int value) {
        for (int i = arr.length - 1; i > 0; i--) {
            arr[i] = arr[i - 1];
        }
        arr[0] = value;
    }

    private static void addAtIndex(int[] arr, int index, int value) {
        for (int i = arr.length - 1; i > index; i--) {
            arr[i] = arr[i - 1];
        }
        arr[index] = value;
    }

    private static void addLast(int[] arr, int value) {
        arr[arr.length - 1] = value;
    }
}

// 결과
배열의 첫번째 위치에 3 추가 o(n)
[3, 1, 2, 0, 0]
배열의 특정 위치에 추가 o(n)
[3, 1, 2, 4, 0]
배열의 마지막 위치에 추가 o(1)
[3, 1, 2, 4, 5]

Process finished with exit code 0

2.5. 배열의 한계

배열은 가장 기본적인 자료 구조이고, 특히 인덱스를 사용할 때 최고의 효율이 나온다.

하지만 이런 배열에는 큰 단점이있다.

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

배열처럼 처음부터 정적으로 길이가 정해져있는 것이 아니라,

동적으로 언제든지 길이를 늘리고 줄일 수 있는 자료 구조가 있다면 편리할 것이다.


3. 직접 구현하는 배열 리스트 - 시작해보기

**배열(Array)**의 경우에는 다음의 단점들이 존재했다.

  • 배열의 길이를 동적으로 변경할 수 없음
  • 데이터를 추가하기 불편하며, 배열 추가하는 코드를 직접 작성해야 한다.

→ 배열의 단점을 해결하기 위한 자료 구조를 List(리스트)라고 한다.

List 자료구조 : 순서가 있고 중복을 허용하는 자료 구조

**배열과 리스트의 차이점

  • 배열 : 순서가 있고 중복을 허용하지만 크기가 정적으로 고정된다.
  • 리스트 : 순서가 있고 중복을 허용하지만 크기가 동적으로 변할 수 있다.**

 

3.1. MyArrayList 구현 - V1

package collection.array;

import java.util.Arrays;

public class MyArrayListV1 {
    // 배열의 크기
    private static final int DEFAULT_CAPACITY = 5;

    // 다양한 타입의 데이터를 보관하기 위해 Object 타입의 배열을 사용!
    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;
    }
    
    // Arrays.copyOf(elementData, size) : size 크기의 배열을 새로 만듬
    // toString() 출력 시 의미 없는(none) 값을 출력하지 않기 위해 사용함
    @Override
    public String toString() {
        return Arrays.toString(Arrays.copyOf(elementData, size)) + " size=" +
                size + ", capacity=" + elementData.length;
    }
}

Main 클래스

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:30)
	at collection.array.MyArrayListV1Main.main(MyArrayListV1Main.java:31)

3.1.1. 데이터 추가

list.add("a") 수행 시, [a] size=1, capacity=5

 

 

 

list.add(”b”) 수행 시, [a, b] size=2, capacity=5

 

 

3.1.2. 데이터 변경

list.set(2, "z") 수행 시, [a, b, z] size=3, capacity=5

 

 

3.1.3. 범위 초과 시

size가 배열의 크기인 capacity에 도달하면 데이터를 더이상 추가할 수 없고 예외가 발생하게 된다.

 

 


4. 직접 구현하는 배열 리스트 - 동적 배열

package collection.array;

import java.util.Arrays;

public class MyArrayListV2 {
    // 배열의 크기
    private static final int DEFAULT_CAPACITY = 5;

    // 다양한 타입의 데이터를 보관하기 위해 Object 타입의 배열을 사용!
    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) {
        // V1에 비해 추가된 부분
        if (size == elementData.length) {
            grow();
        }

        elementData[size] = e;
        size++;
    }

    // V1에 비해 추가된 메서드
    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;
    }
    
    // Arrays.copyOf(elementData, size) : size 크기의 배열을 새로 만듬
    // toString() 출력 시 의미 없는(none) 값을 출력하지 않기 위해 사용함
    @Override
    public String toString() {
        return Arrays.toString(Arrays.copyOf(elementData, size)) + " size=" +
                size + ", capacity=" + elementData.length;
    }
}
  • 추가된 부분
    • add() : 데이터 추가하기 전에 size와 element.length를 비교하여 grow() 메서드 호출
    • grow() : 기존 배열을 기반으로 새로운 배열을 만들고 크기를 2배 늘려준다.
      • Arrays.copyOf(기존배열, 새로운길이) : 새로운 길이로 배열을 생성하고 기존 배열의 값을 그대로 복사해준다.

Main 코드

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

 

 

4.1. 배열의 크기를 초과하면 어찌 되는가?

[1] add() 메서드가 호출될 때 size가 capacity에 초과하게 된다.

[2] 초과하면 grow() 메서드가 호출되며 2배 큰 크기로 새로운 배열이 생성된다.

[3] 새로운 배열에 값을 복사한다.

 

 

[4] elementData가 바라봐야 할 참조값을 변경한다.

[5] 그제서야 add()메서드는 데이터를 추가한다.

이후에는 GC에 의해 기존 elementData가 바라보던 배열은 참조하는 값이 없으므로 GC 대상이 된다.

 

(참고)

예제를 단순화하기 위해 여기선 2배씩 증가시켰지만, 보통 50% 정도 증가하는 방법을 사용한다고 한다.

 

 

5. 직접 구현하는 배열 리스트3 - 기능 추가

  • add(index, 데이터) : index 위치에 데이터를 추가한다.
  • remove(index) : index 위치의 데이터를 삭제한다.

앞서 만든 add()는 구현이 단순했다.

하지만 앞이나 중간에 데이터를 추가하거나 삭제하면 기존 데이터의 위치들을 이동시키고 데이터를 추가해야 하기 때문에 구현이 복잡해진다.

→ O(n)으로 표현할 수 있다.

package collection.array;

import java.util.Arrays;

public class MyArrayListV3 {
    // 배열의 크기
    private static final int DEFAULT_CAPACITY = 5;

    // 다양한 타입의 데이터를 보관하기 위해 Object 타입의 배열을 사용!
    private Object[] elementData;

    // 리스트의 크기
    private int size = 0;

    public MyArrayListV3() {
        elementData = new Object[DEFAULT_CAPACITY];
    }

    public MyArrayListV3(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++;
    }

    // V2에 비해 코드 추가된 부분
    public void add(int index, Object e) {
        if (size == elementData.length) {
            grow();
        }
        shiftRightFrom(index);
        elementData[index] = e;
        size++;
    }

    // V2에 비해 추가된 부분
    // 요소의 마지막부터 index까지 오른쪽으로 한칸씩 밀어주기
    private 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);
    }

    // 인덱스에 있는 항목 조회
    public Object get(int index) {
        return elementData[index];
    }

    // 인덱스에 있는 항목을 변경
    public Object set(int index, Object element) {
        Object oldValue = get(index);
        elementData[index] = element;
        return oldValue;
    }

    // V2에 비해 추가된 메서드
    public Object remove(int index) {
        Object oldValue = get(index);
        shiftLeftFrom(index);

        size--;
        elementData[size] = null;
        return oldValue;
    }

    // V2에 비해 추가된 메서드
    // 요소의 index부터 마지막까지 왼쪽으로 밀기
    private void shiftLeftFrom(int index) {
        for (int i = index; i < size - 1; i++) {
            elementData[i] = elementData[i + 1];
        }
    }

    // 검색 기능
    public int indexOf(Object o) {
        for (int i = 0; i < size; i++) {
            if (o.equals(elementData[i])) {
                return i;
            }
        }
        return -1;
    }
    
    // Arrays.copyOf(elementData, size) : size 크기의 배열을 새로 만듬
    // toString() 출력 시 의미 없는(none) 값을 출력하지 않기 위해 사용함
    @Override
    public String toString() {
        return Arrays.toString(Arrays.copyOf(elementData, size)) + " size=" +
                size + ", capacity=" + elementData.length;
    }
}

Main 코드

package collection.array;

public class MyArrayListV3Main {
    public static void main(String[] args) {
        MyArrayListV3 list = new MyArrayListV3();

        //마지막에 추가 //O(1)
        list.add("a");
        list.add("b");
        list.add("c");
        System.out.println(list);

        //원하는 위치에 추가
        System.out.println("addLast");
        list.add(3, "addLast"); //O(1)
        System.out.println(list);

        System.out.println("addFirst");
        list.add(0, "addFirst"); //O(n)
        System.out.println(list);

        //삭제
        Object removed1 = list.remove(4);//remove Last O(1)
        System.out.println("remove(4)="+ removed1);
        System.out.println(list);

        Object removed2 = list.remove(0);//remove First O(n)
        System.out.println("remove(0)=" + removed2);
        System.out.println(list);
    }
}

// 결과
[a, b, c] size=3, capacity=5
addLast
[a, b, c, addLast] size=4, capacity=5
addFirst
[addFirst, a, b, c, addLast] size=5, capacity=5
remove(4)=addLast
[addFirst, a, b, c] size=4, capacity=5
remove(0)=addFirst
[a, b, c] size=3, capacity=5

 

 

 

6. 직접 구현하는 배열 리스트4 - 제네릭

앞서 만든 MyArrayList 들은 Object 를 입력받기 때문에 아무 데이터나 입력할 수 있고, 또 결과로 Object 를 반환한다.

따라서 필요한 경우 다운 캐스팅을 해야하고, 또 타입 안전성이 떨어지는 단점이 있다.

package collection.array;
public class MyArrayListV3BadMain {
    public static void main(String[] args) {
        MyArrayListV3 numberList = new MyArrayListV3();
        // 숫자만 입력 하기를 기대
        numberList.add(1);
        numberList.add(2);
	      numberList.add("문자3"); //문자를 입력
        System.out.println(numberList);
        // Object를 반환하므로 다운 캐스팅 필요
        Integer num1 = (Integer) numberList.get(0);
        Integer num2 = (Integer) numberList.get(1);
        // ClassCastException 발생, 문자를 Integer로 캐스팅
        Integer num3 = (Integer) numberList.get(2);
    }
}

// 결과
[1, 2, 문자3] size=3, capacity=5
Exception in thread "main" java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Integer (java.lang.String and java.lang.Integer are in module java.base of loader 'bootstrap')
	at collection.array.MyArrayListV3BadMain.main(MyArrayListV3BadMain.java:14)

  • Object를 받아서 저장하기 때문에 자바의 모든 타입을 다 저장할 수 있다.
    • 따라서 숫자를 입력하다가 문자를 입력해도 자바 입장에서 아무런 문제가 되지 않는다.
  • 값을 꺼낼 때 Object를 반환하기 때문에 원래 입력한 타입으로 받으려면 다운 캐스팅을 해야한다.
    • 입력한 데이터를 정확히 알고 있지 않으면 예외가 발생할 수 있다.

→ 제네릭을 도입하면 타입 안정성을 확보할 수 있게 된다.

package collection.array;

import java.util.Arrays;

public class MyArrayListV4<E> {
    // 배열의 크기
    private static final int DEFAULT_CAPACITY = 5;

    // 다양한 타입의 데이터를 보관하기 위해 Object 타입의 배열을 사용!
    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++;
    }

    // V2에 비해 코드 추가된 부분
    public void add(int index, E e) {
        if (size == elementData.length) {
            grow();
        }
        shiftRightFrom(index);
        elementData[index] = e;
        size++;
    }

    // V2에 비해 추가된 부분
    // 요소의 마지막부터 index까지 오른쪽으로 한칸씩 밀어주기
    private 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);
    }

    // 인덱스에 있는 항목 조회
    @SuppressWarnings("unchecked")
    public E get(int index) {
        return (E) elementData[index];
    }

    // 인덱스에 있는 항목을 변경
    public E set(int index, E element) {
        E oldValue = get(index);
        elementData[index] = element;
        return oldValue;
    }

    // V2에 비해 추가된 메서드
    public E remove(int index) {
        E oldValue = get(index);
        shiftLeftFrom(index);

        size--;
        elementData[size] = null;
        return oldValue;
    }

    // V2에 비해 추가된 메서드
    // 요소의 index부터 마지막까지 왼쪽으로 밀기
    private void shiftLeftFrom(int index) {
        for (int i = index; i < size - 1; i++) {
            elementData[i] = elementData[i + 1];
        }
    }

    // 검색 기능
    public int indexOf(E o) {
        for (int i = 0; i < size; i++) {
            if (o.equals(elementData[i])) {
                return i;
            }
        }
        return -1;
    }
    
    // Arrays.copyOf(elementData, size) : size 크기의 배열을 새로 만듬
    // toString() 출력 시 의미 없는(none) 값을 출력하지 않기 위해 사용함
    @Override
    public String toString() {
        return Arrays.toString(Arrays.copyOf(elementData, size)) + " size=" +
                size + ", capacity=" + elementData.length;
    }
}
  • MyArrayListV4<E> : 제네릭 타입 선언
  • Object로 입력받고 출력했던 곳을 매개변수 E로 변경
  • Object[] elementData는 그대로 유지
    • Why ? 제네릭은 런타임에 이레이저에 의해 타입 정보가 사라진다. 따라서 런타임에 타입 정보가 필요한 생성자에 사용할 수 없고 Object를 그대로 사용해야 한다.
        private Object[] elementData;
    ...
    ...
        public MyArrayListV4() {
            elementData = new Object[DEFAULT_CAPACITY];
        }
    
        public MyArrayListV4(int initialCapacity) {
            elementData = new Object[initialCapacity];
        }
    
  • Object[] elementData를 그대로 유지해도 괜찮을까?
    • 데이터 추가 시 : <E> 타입만 추가할 수 있도록 강제되기 때문에 OK
    • 데이터 조회 시 : 데이터를 꺼낼 때 항상 (E)로 다운 캐스팅을 한다. <E> 타입만 추가할 수 있도록 강제되었기 때문에 (E)로 다운 캐스팅해도 문제가 되지 않는다.

Main 코드

package collection.array;
public class MyArrayListV4Main {
    public static void main(String[] args) {
        MyArrayListV4<String> stringList = new MyArrayListV4<>();

        stringList.add("a");
        stringList.add("b");
        stringList.add("c");
        String string = stringList.get(0);
        System.out.println("string = " + string);

        MyArrayListV4<Integer> intList = new MyArrayListV4<>();

        intList.add(1);
        intList.add(2);
        intList.add(3);
        Integer integer = intList.get(0);
        System.out.println("integer = " + integer);
    }
}

 

 

 

**생성자에는 제네릭의 타입 매개변수를 사용할 수 없는 한계가 있다. 따라서 배열을 생성할 때 대안으로 Object 배열을 사용해야 한다.

하지만 제네릭이 데이터를 입력받고 반환하는 곳의 타입을 고정해주기 때문에 고정된 타입으로 Object 배열에 데이터를 보관할 수 있게 되며 이로 인해 데이터를 꺼낼 때도 고정된 타입으로 안전하게 다운 캐스팅을 할 수 있게 된다.**

배열 리스트는 중간에 데이터를 추가하거나 삭제할 때 성능이 좋지 않다. O(n)

따라서 이런 단점을 해결한 링크드 리스트(Linked List)를 다음 시간에 알아보자..

 

 

 

 

 

반응형