안녕하세요! 오늘 강의는
ArrayList
이전 강의에 비해 한편으로는 간단하면서도 한편으로는 더 어려울 것입니다. 오늘은 "내부"를 살펴보고 ArrayList
작업 중에 어떤 일이 일어나는지 연구하기 때문에 더 어렵습니다. 반면에, 이번 강의에는 코드가 거의 없을 것입니다. 대부분 그림과 설명입니다. 자, 가봅시다 :) 이미 알고 있듯이 ArrayList
'a 내부에는 데이터 저장소 역할을 하는 일반 배열이 있습니다. 대부분의 경우 목록의 정확한 크기를 지정하지 않습니다. 하지만 내부 배열에는 어느 정도의 크기가 있어야 합니다! 이것은 사실이다. 기본 크기는 [10] 입니다 .
public static void main(String[] args) {
ArrayList<Car> cars = new ArrayList<>();
}
먼저 새 요소를 추가하는 모습을 살펴보겠습니다. 우선, 내부 배열에 충분한 공간이 있는지 , 하나 이상의 요소가 들어갈 수 있는지 확인합니다 . 공백이 있으면 새 요소가 목록 끝에 추가됩니다. "끝까지"라고 말할 때 배열의 마지막 셀을 의미하는 것은 아닙니다(이상할 것입니다). 이는 마지막 현재 요소 옆의 셀을 나타냅니다. 해당 인덱스는 와 같습니다 cars.size()
. 현재 목록이 비어 있습니다( cars.size() = 0
). 따라서 인덱스가 있는 셀에 새 요소가 추가됩니다 0
.
ArrayList<Car> cars = new ArrayList<>();
Car ferrari = new Car("Ferrari 360 Spider");
cars.add(ferrari);
여기에서는 모든 것이 명확합니다. 중간, 즉 여러 요소 사이에 삽입이 수행되면 어떻게 될까요?
public static void main(String[] args) {
ArrayList<Car> cars = new ArrayList<>();
Car ferrari = new Car("Ferrari 360 Spider");
Car bugatti = new Car("Bugatti Veyron");
Car lambo = new Car("Lamborghini Diablo");
Car ford = new Car("Ford Modneo");
cars.add(ferrari);
cars.add(bugatti);
cars.add(lambo);
cars.add(1, ford);//добавляем ford в ячейку 1, которая уже занята
}
이번에도 먼저 배열에 충분한 공간이 있는지 확인합니다. 공간이 충분하면 새 요소를 삽입하는 셀부터 요소가 오른쪽으로 이동됩니다 . 인덱스 1을 사용하여 셀에 붙여넣습니다. 즉, 셀 3의 요소가 셀 4에, 요소 2가 셀 3에, 요소 1이 셀 2에 복사됩니다. 그런 다음 새 요소가 제자리에 붙여넣어집니다. 이전 요소( bugatti
)는 이미 해당 위치에서 새 위치로 복사되었습니다. 이제 배열에 삽입할 공간이 없으면 이 프로세스가 어떻게 발생하는지 알아 보겠습니다. 물론, 먼저 충분한 공간이 있는지 확인합니다. 공간이 부족하다고 판단되면 ArrayList
'a' 내부에 (OldArray의 크기 * 1.5) + 1 크기의 새로운 배열이 생성되는데, 우리의 경우 새 배열의 크기는 16셀이 됩니다. 모든 현재 요소가 즉시 복사됩니다. 이전 배열은 가비지 수집기에 의해 삭제되고 새로 확장된 배열만 남게 됩니다. 이제 새 요소를 위한 여유 공간이 생겼습니다. 우리는 그것을 점유된 셀 3에 붙여넣습니다. 이제 익숙한 절차가 시작됩니다. 인덱스 3에서 시작하는 모든 요소는 한 셀 오른쪽으로 이동되고 새 요소가 자동으로 추가됩니다. 이제 삽입이 성공했습니다! 삽입을 정리했습니다. 이제 요소 제거 에 대해 이야기하겠습니다 . 기억하시는 것처럼 배열 작업을 할 때 문제가 발생했습니다. 배열을 삭제해도 배열에 "구멍"이 남아 있었습니다. 유일한 해결책은 요소가 삭제될 때마다 왼쪽으로 이동하는 것이 었고 , 이동을 위한 코드를 직접 작성해야 했습니다. ArrayList
동일한 원리로 작동하지만 이 메커니즘은 이미 자동으로 구현되었습니다. 결과는 다음과 같습니다. 결국 원하는 결과를 얻습니다. 요소가 lambo
성공적으로 삭제되었습니다. 여기서는 중간 부분을 제거했습니다. 다른 요소를 모두 이동하지 않고 원하는 요소가 제거되므로 목록 끝에서 삭제하는 것이 더 빠르다는 것은 분명합니다. 내부 어레이의 크기와 메모리 내 저장 공간을 다시 살펴보겠습니다. 어레이 확장은 일정량의 리소스를 사용하는 프로세스입니다. ArrayList
따라서 최소 100개의 요소가 있다는 것을 확실히 알고 있는 경우 기본 크기로 생성하면 안 됩니다 . 100번째 요소를 삽입할 때마다 내부 배열은 6배로 확장되며 매번 모든 요소가 전송됩니다.
- 10개 요소에서 16개 요소로
- 16개 요소에서 25개 요소로
- 25일부터 38일까지
- 38에서 58까지
- 58에서 88까지
- 88에서 133까지 (공식에 따라 (기존 배열의 크기 * 1.5) + 1)
ArrayList<Car> cars = new ArrayList<>(100);
이제 100개 요소의 배열이 메모리에 즉시 할당되며, 이는 확장 시 리소스가 낭비되지 않으므로 더욱 효율적입니다. 동전의 반대편도 있습니다. 내부 배열 에서 객체를 제거해도 ArrayList
크기가 자동으로 줄어들지 않습니다. ArrayList
예를 들어, 완전히 채워진 88개 요소의 내부 배열이 있습니다 . 프로그램이 작동하는 동안 77개 요소를 제거하고 11개만 남습니다. 문제가 무엇인지 이미 짐작하셨나요? 물론, 메모리를 비효율적으로 사용합니다! 우리는 11개의 셀만 사용하는 반면 88개의 요소에 메모리를 할당했습니다. 이는 필요한 것보다 8배 더 많은 것입니다! 이 경우 최적화를 수행하려면 특수 클래스 메소드인 를 사용할 수 ArrayList
있습니다 trimToSize()
. 내부 배열의 길이를 현재 배열에 저장된 요소 수로 "절단"합니다. 이제 필요한 만큼의 메모리가 할당됩니다! :)
GO TO FULL VERSION