[Java] Class Vector
JavaCollection Framework
데이터 군을 저장하는 클래스들을 표준화한 설계
컬렉션 Collection : 다수의 데이터. 데이터 그룹
프레임웍 Framework : 표준화된 프로그래밍 방식.
Class Vector
- 객체에 대한 참조값을 저장하는 배열
서로 다른 타입을 가지는 참조형 데이터를 저장. 기본형 데이터는 Wrapper로 변형 후 저장 가능.
- List 인터페이스를 구현
저장된 순서를 유지한다.
- Object 배열을 이용하여 데이터를 순차적으로 저장
용량 변경 비효율적. 읽기, 저장하기 효율적.
- 처음 인스턴스 생성 시, 저장할 데이터의 개수를 잘 고려하여 충분한 용량의 인스턴스를 생성한다.
자동적으로 크기가 늘어나긴 하지만 그 과정에서 처리시간이 많이 소요된다.
ArrayList와 Vector
배열을 이용한 자료구조는 데이터를 읽어오고 저장할 때 효율이 좋다.
용량을 변경해야 할 때, 새로운 배열을 생성한 후 기존의 배열로부터 새로 생성된 배열로 데이터를 복사해야 하는 단점이 있다.
import java.util.Vector;
public class Test {
public static void main(String[] args) {
Vector<String> 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 static void print(Vector v) {
System.out.println("size : " + v.size() + " / capacity : " + v.capacity());
}
}
- 용량(capacity)이 5인 Vector v에 객체 3개 저장
0x100 | 0x900 | 0x800 | 0x700 | null | null |
---|
v | 0x900 | 0x800 | 0x700 |
---|---|---|---|
0x100 | 1 | 2 | 3 |
- v.trimToSize()
빈 공간 제거
배열의 크기를 변경할 수 없기 때문에 새로운 배열을 생성해서 그 주소값을 변수 v에 할당한다.
기존 Vector 인스턴스는 제거된다.
0x200 | 0x900 | 0x800 | 0x700 |
---|
v | 0x900 | 0x800 | 0x700 |
---|---|---|---|
0x200 | 1 | 2 | 3 |
- v.ensureCapacity(6)
capacity가 최소한 6이 되도록 한다.
만일 크기가 6이상이라면 아무 일도 일어나지 않는다.
0x300 | 0x900 | 0x800 | 0x700 | null | null | null |
---|
v | 0x900 | 0x800 | 0x700 |
---|---|---|---|
0x300 | 1 | 2 | 3 |
- v.setSize(7)
capacity가 충분하지 않을 경우 자동적으로 기존의 크기보다 2배의 크기로 증가한다.
0x400 | 0x900 | 0x800 | 0x700 | null | null | null | null | null | null | null | null | null |
---|
v | 0x900 | 0x800 | 0x700 |
---|---|---|---|
0x400 | 1 | 2 | 3 |
- v.clear()
v의 모든 요소를 삭제한다.
0x400 | null | null | null | null | null | null | null | null | null | null | null | null |
---|
v | |||
---|---|---|---|
0x400 |
Vector
다음 예제는 Vector 클래스의 실제 코드를 바탕으로 이해하기 쉽게 재구성한 것이다.
package blog;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
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 void add(int arg0, Object arg1) {
// TODO Auto-generated method stub
}
@Override
public boolean addAll(Collection arg0) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean addAll(int arg0, Collection arg1) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean contains(Object arg0) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean containsAll(Collection arg0) {
// TODO Auto-generated method stub
return false;
}
@Override
public int indexOf(Object o) {
// TODO Auto-generated method stub
return 0;
}
@Override
public Iterator iterator() {
// TODO Auto-generated method stub
return null;
}
@Override
public int lastIndexOf(Object o) {
// TODO Auto-generated method stub
return 0;
}
@Override
public ListIterator listIterator() {
// TODO Auto-generated method stub
return null;
}
@Override
public ListIterator listIterator(int index) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean removeAll(Collection c) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean retainAll(Collection c) {
// TODO Auto-generated method stub
return false;
}
@Override
public Object set(int index, Object element) {
// TODO Auto-generated method stub
return null;
}
@Override
public List subList(int fromIndex, int toIndex) {
// TODO Auto-generated method stub
return null;
}
@Override
public Object[] toArray(Object[] a) {
// TODO Auto-generated method stub
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 |
2 | 4 | 4 | null | (null) |
4 | (null) | (null) | (null) | (null) |
5 | (null) | (null) | (null) | (null) |
배열에 객체를 순차적으로 저장할 때, 객체를 마지막에 지정된 것부터 삭제할 때
System.arraycopy()를 호출하지 않으므로 작업시간이 짧다.
배열의 중간에 위치한 객체를 추가하거나, 삭제할 때는 System.arraycopy()를 호출해서
다른 데이터의 위치를 이동시켜 줘야 하기 때문에 다루는 데이터의 개수가 많을 수록 작업시간이 오래 걸린다.
참고 서적: 자바의 정석 3판 2