здрасти Днешният урок
Ще бъде по-трудно, защото днес ще погледнем под капака
ArrayList
ще бъде едновременно по-лесен и по-труден от предишните уроци.
ArrayList
и ще проучим Howво се случва по време на различни операции. От друга страна, този урок няма да има почти ниHowъв code. Това са предимно снимки и обяснения. Е, да тръгваме :) Както вече знаете, ArrayList
има обикновен масив вътре, който действа като хранorще на данни. В повечето случаи не посочваме точния размер на списъка. Но вътрешният масив трябва да има няHowъв размер! И така става. Размерът му по подразбиране е 10 .
public static void main(String[] args) {
ArrayList<Car> cars = new ArrayList<>();
}
Първо, нека видим How изглежда добавянето на нови елементи. Първата работа е да се провери дали вътрешният масив има достатъчно място във вътрешния масив и дали ще се побере още един елемент. Ако има място, новият елемент се добавя в края на списъка. Когато казваме "до края", нямаме предвид последната позиция в масива (това би било странно). Имаме предвид позицията след последния текущ елемент. Индексът му ще бъде 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);// add ford to cell 1, which is already occupied
}
Отново първо се проверява дали има достатъчно място в масива. Ако има достатъчно място, тогава елементите се изместват надясно , започвайки от позицията, където вмъкваме новия елемент. Вмъкваме в позиция 1. С други думи, елементът от позиция 3 се копира в позиция 4, елемент 2 в позиция 3 и елемент 1 в позиция 2. След това нашият нов елемент се вмъква на негово място. Предишният елемент (bugatti) вече е копиран от там на нова позиция. Сега нека да разгледаме How се случва този процес, ако няма места за вмъкване на нови елементи в масива. Естествено, първо се проверява дали има достатъчно място. Ако няма достатъчно място, тогава се създава нов масив вътре вArrayList
чийто размер е размерът на стария масив, умножен по 1,5 плюс 1. В нашия случай размерът на новия масив ще бъде 16. Всички текущи елементи ще бъдат копирани веднага там. Старият масив ще бъде изтрит от събирача на отпадъци и ще остане само новият, разширен масив. Сега има място за нов елемент. Вмъкваме го на позиция 3, която е заета. Сега започва познатата proceduresа. Всички елементи, започващи с индекс 3, се изместват една позиция надясно и новият елемент се добавя тихо. И вмъкването е готово! И сме готови с вмъкването. Сега нека поговорим за премахването на елементи . Ще си спомните, че се натъкнахме на проблем при работа с масиви: премахването на елементи прави „дупки“ в масива.с всяко премахване и трябваше да пишем собствен code всеки път, за да извършим тази смяна. ArrayList следва същия принцип, но вече прилага този механизъм. Ето How изглежда: И в крайна сметка получаваме това, което искаме: Елементът lambo
е премахнат. Тук премахнахме елемент от средата. Ясно е, че премахването на елемент от края на списъка е по-бързо, тъй като елементът просто се премахва, без да е необходимо да се преместват всички останали. Нека поговорим отново за момент за размерите на вътрешния масив и How е подреден в паметта. Разширяването на масив отнема известни ресурси. Съответно, не създавайтеArrayList
с размера по подразбиране, ако сте сигурни, че ще има поне 100 елемента. Вътрешният масив ще трябва да бъде разширен 6 пъти до момента, в който вмъкнете 100-ия елемент, и всички елементи ще трябва да се изместват всеки път.
- от 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: Вече познахте ли Howъв е проблемът? Разбрахте, неефективно използване на паметта! Тук използваме само 11 позиции, но сме заделor памет за 88 елемента. Това е 8 пъти повече, отколкото ни трябва! В този случай можем да оптимизираме използването на нашата памет с един от ArrayList
специалните методи на класа:trimToSize()
. Този метод "подрязва" дължината на вътрешния масив до броя на елементите, съхранявани в момента в него. Сега сме разпределor само толкова памет, колкото ни е необходима! :)
GO TO FULL VERSION