Collection Framework

데이터 군을 저장하는 클래스들을 표준화한 설계
컬렉션 Collection :  다수의 데이터. 데이터 그룹
프레임웍 Framework :  표준화된 프로그래밍 방식.





Java.util.Vector Class

객체에 대한 참조값을 저장하는 배열 → 서로 다른 타입을 가지는 참조형 데이터를 저장. 기본형 데이터는 Wrapper로 변형 후 저장 가능.
List 인터페이스를 구현 → 저장된 순서를 유지한다.
Object 배열을 이용하여 데이터를 순차적으로 저장 → 용량 변경 비효율적. 읽기, 저장하기 효율적.
처음 인스턴스 생성 시, 저장할 데이터의 개수를 잘 고려하여 충분한 용량의 인스턴스를 생성한다.
자동적으로 크기가 늘어나긴 하지만 그 과정에서 처리시간이 많이 소요된다.



ArrayList와 Vector

배열을 이용한 자료구조는 데이터를 읽어오고 저장할 때 효율이 좋다.
용량을 변경해야 할 때, 새로운 배열을 생성한 후 기존의 배열로부터 새로 생성된 배열로 데이터를 복사해야 하는 단점이 있다.
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...

        Vector v = new Vector(5);
        v.add("1");
        v.add("2");
        v.add("3");
        print(v);                      // size : 3 / capacity : 5

        v.trimToSize();
        print(v);                      // size : 3 / capacity : 3

        v.ensureCapacity(6);
        print(v);                      // size : 3 / capacity : 6

        v.setSize(7);
        print(v);                      // size : 7 / capacity : 12

        v.clear();
        print(v);                      // size : 0 / capacity : 12

    }

    public void print(Vector v) {
        Log.d("TAG_TEST", "size : " + v.size() + " / capacity : " + v.capacity());
    }
}

•  용량capacity이 5인 Vector v에 객체 3개 저장
v 0x900 0x800 0x700
0x100 1 2 3
  0x100
0x900 0x800 0x700 null null


•  v.trimToSize()
    빈 공간 제거
    배열의 크기를 변경할 수 없기 대문에 새로운 배열을 생성해서 그 주소값을 변수 v에 할당한다.
    기존 Vector 인스턴스는 제거된다.
v 0x900 0x800 0x700
0x200 1 2 3
  0x200
0x900 0x800 0x700


•  v.ensureCapacity(6)
    capacity가 최소한 6이 되도록 한다.
    만일 크기가 6이상이라면 아무 일도 일어나지 않는다.
v 0x900 0x800 0x700
0x300 1 2 3
  0x300
0x900 0x800 0x700 null null null


•  v.setSize(7)
    capacity가 충분하지 않을 경우 자동적으로 기존의 크기보다 2배의 크기로 증가한다.
v 0x900 0x800 0x700
0x400 1 2 3
  0x400
0x900 0x800 0x700 null null null null null null null null null


•  v.clear()
    v의 모든 요소를 삭제한다.
v
0x400
  0x400
null null null null null null null null null null null null




Vector

다음 예제는 Vector 클래스의 실제 코드를 바탕으로 이해하기 쉽게 재구성한 것이다.
public class MyVector implements List{
    Object[] date = null;
    int capacity = 0;
    int size = 0;

    MyVector(int capacity) {
        if (capacity < 0) {
            throw new IllegalArgumentException("유효하지 않은 값입니다. :" + capacity);
        }

        this.capacity = capacity;
        date = new Object[capacity];
    }

    MyVector() {
        this(10);
    }

    // 최소한의 저장 공간 확보
    public void ensureCapacity(int minCapacity) {
        if (minCapacity - date.length > 0) {
            setCapacity(minCapacity);
        }
    }

    public boolean add(Object obj) {
        ensureCapacity(size + 1); // 새 객체 저장하기 전에 공간 확보
        date[size++] = obj;
        return true;
    }

    public Object get(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("범위를 벗어났습니다.");
        }
        return date[index];
    }

    public Object remove(int index) {
        Object oldObj = null;

        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("범위를 벗어났습니다.");
        }
        oldObj = date[index];

        // 삭제하려는 객체가 마지막 객체가 아니라면, 배열 복사를 통해 빈자리를 채워야 한다.
        if (index != size - 1) {
            System.arraycopy(date, index + 1, date, index, size - index - 1);
        }

        // 마지막 데이터를 null. 마지막 요소의 index = size-1
        date[size - 1] = null;
        size--;
        return oldObj;
    }

    public boolean remove(Object obj) {
        for (int i = 0; i < size; i++) {
            if (obj.equals(date[i])) {
                remove(i);
                return true;
            }
        }
        return false;
    }

    public void trimToSize() {
        setCapacity(size);
    }

    public void setCapacity(int capacity) {
        if (this.capacity == capacity) return; // 크기가 같으면 변경 취소

        Object[] temp = new Object[capacity];
        System.arraycopy(date, 0, temp, 0, size);
        date = temp;
        this.capacity = capacity;
    }

    public void clear() {
        for (int i = 0; i < size; i++) {
            date[i] = null;
        }
        size = 0;
    }

    public Object[] toArray() {
        Object[] result = new Object[size];
        System.arraycopy(date, 0, result, 0, size);

        return result;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public int capacity() {
        return capacity;
    }

    public int size() {
        return size;
    }

/* interface List로부터 상속받은 method들 */

    @Override
    public Object set(int index, Object element) { return null; }

    @Override
    public void add(int index, Object element) { }

    @Override
    public int indexOf(Object o) { return 0; }

    @Override
    public int lastIndexOf(Object o) { return 0; }

    @Override
    public ListIterator listIterator() { return null; }

    @NonNull
    @Override
    public ListIterator listIterator(int index) { return null; }

    @NonNull
    @Override
    public List subList(int fromIndex, int toIndex) { return null; }

    @Override
    public boolean addAll(@NonNull Collection c) { return false; }

    @Override
    public boolean addAll(int index, @NonNull Collection c) { return false; }

    @Override
    public boolean retainAll(@NonNull Collection c) { return false; }

    @Override
    public boolean removeAll(@NonNull Collection c) { return false; }

    @Override
    public boolean containsAll(@NonNull Collection c) { return false; }

    @NonNull
    @Override
    public Object[] toArray(@NonNull Object[] a) { return new Object[0]; }

    @Override
    public boolean contains(Object o) { return false; }

    @NonNull
    @Override
    public Iterator iterator() { return null; }
}

•  Object remove(int index)
    1. 삭제할 객체의 바로 아래에 있는 데이터를 한 칸씩 위로 복사해서 삭제할 객체를 덮어쓰는 방식으로 처리한다.
    2. 마지막 데이터는 null로 변경한다.
    3. 데이터가 삭제되어 데이터의 개수가 줄었으므로 size의 값을 1 감소시킨다.
index 기존 덮기 변경 감소
0 1 1 1 1
1 2 3 3 3
2 3 4 4 4
3 4 4 null (null)
4 (null) (null) (null) (null)
5 (null) (null) (null) (null)
    배열에 객체를 순차적으로 저장할 때, 객체를 마지막에 지정된 것부터 삭제할 때 System.arraycopy()를 호출하지 않으므로 작업시간이 짧다.
    배열의 중간에 위치한 객체를 추가하거나, 삭제할 때는 System.arraycopy()를 호출해서
    다른 데이터의 위치를 이동시켜 줘야 하기 때문에 다루는 데이터의 개수가 많을 수록 작업시간이 오래 걸린다.




•  참고 서적: 자바의 정석 3판 2