[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 |