02/06/2002
I Javas omfattende økosystem af datastrukturer står ArrayList som en af de mest anvendte og alsidige klasser. Den er en del af Java Collections Framework og findes i java.util-pakken. For mange udviklere, både nye og erfarne, er ArrayList det foretrukne valg, når der er behov for en dynamisk liste af objekter. I modsætning til traditionelle arrays, som har en fast størrelse ved oprettelse, tilbyder ArrayList fleksibiliteten til at vokse og krympe efter behov, hvilket forenkler håndteringen af datasamlinger, hvis størrelse ikke er kendt på forhånd.

Denne artikel vil give en dybdegående gennemgang af ArrayList i Java. Vi vil udforske dens kernefunktioner, hvordan man opretter og manipulerer den, dens fordele og ulemper, samt kaste lys over det ofte misforståede koncept omkring generics og typen ArrayList<T>.
Hvad er en Java ArrayList?
En ArrayList er i bund og grund en implementering af List-interfacet, der bruger et resizable array i baggrunden. Det betyder, at den kombinerer fordelene ved et array, såsom hurtig, indekseret adgang til elementer, med fleksibiliteten fra en liste, der kan ændre størrelse dynamisk. Når du tilføjer elementer til en ArrayList, og den interne array-kapacitet overskrides, opretter den automatisk et nyt, større array og kopierer de gamle elementer over. Denne proces er automatiseret, så udvikleren ikke behøver at bekymre sig om manuel hukommelsesstyring.
Nøgleegenskaber ved ArrayList
- Dynamisk Størrelse: Som nævnt er den største fordel, at en ArrayList kan vokse og krympe automatisk, når elementer tilføjes eller fjernes.
- Indekseret Adgang: Elementer kan tilgås direkte via deres numeriske indeks (position i listen), ligesom med et almindeligt array. Dette giver en meget hurtig læseadgang (O(1) kompleksitet).
- Understøtter Generics: ArrayList er en generisk klasse, hvilket betyder, at du kan specificere den type objekter, den skal indeholde. Dette sikrer typetjek ved kompileringstid og forhindrer runtime-fejl forårsaget af forkerte datatyper. Eksempel:
ArrayList<String>kan kun indeholde String-objekter. - Ikke-synkroniseret: Som standard er ArrayList ikke trådsikker (thread-safe). Hvis flere tråde skal tilgå og modificere en ArrayList samtidigt, skal synkronisering håndteres manuelt, f.eks. ved at bruge
Collections.synchronizedList(). - Tillader Null og Duplikater: Du kan frit tilføje
null-værdier og duplikerede elementer til en ArrayList. - Bevarende af Indsættelsesrækkefølge: Den rækkefølge, elementer tilføjes i, er den rækkefølge, de opbevares og itereres i. Dette kaldes også indsættelsesrækkefølge.
Konstruktører i ArrayList
For at oprette en ArrayList skal du instantiere et objekt af ArrayList-klassen. Der findes tre primære konstruktører til dette formål:
ArrayList()Denne konstruktør opretter en tom liste med en initial standardkapacitet (typisk 10). Kapaciteten udvides automatisk, når det er nødvendigt.
// Opretter en tom ArrayList til heltal ArrayList<Integer> talListe = new ArrayList<>();ArrayList(int initialCapacity)Bruges til at oprette en tom liste med en specificeret startkapacitet. Dette kan forbedre ydeevnen, hvis du ved på forhånd, hvor mange elementer listen cirka skal indeholde, da det minimerer antallet af interne re-allokeringer af arrayet.
// Opretter en liste med plads til 50 elementer fra start ArrayList<Double> priser = new ArrayList<>(50);ArrayList(Collection<? extends E> c)Denne konstruktør opretter en liste, der indeholder alle elementerne fra en anden samling (Collection). Elementerne tilføjes i den rækkefølge, de returneres af samlingens iterator.

A list is defined as the std::list class template inside the header file. where, T: Type of elements in the list. l: Name assigned to the list. In C++, list can be declared and initialized in multiple ways as shown in the below example: Example: In this example, Statement list l1 creates an empty linked list. // Opretter en ny ArrayList baseret på en eksisterende liste List<String> eksisterendeListe = List.of("A", "B", "C"); ArrayList<String> nyListe = new ArrayList<>(eksisterendeListe);
Grundlæggende Operationer: Tilføj, Fjern og Opdater
Når du har oprettet en ArrayList, er de mest almindelige operationer at tilføje, fjerne, læse og opdatere elementer. Lad os se på et praktisk eksempel.
Eksempel på Kode
import java.util.ArrayList; class ArrayListEksempel { public static void main(String[] args) { // Opretter en ArrayList af typen String ArrayList<String> frugter = new ArrayList<>(); // 1. Tilføj elementer til slutningen af listen frugter.add("Æble"); frugter.add("Banan"); System.out.println("Oprindelig liste: " + frugter); // Tilføj et element på et specifikt indeks (position 1) frugter.add(1, "Orange"); System.out.println("Efter tilføjelse på indeks 1: " + frugter); // 2. Fjern et element via dets indeks frugter.remove(0); // Fjerner "Æble" System.out.println("Efter fjernelse af element på indeks 0: " + frugter); // Fjern et element via dets værdi frugter.remove("Banan"); System.out.println("Efter fjernelse af elementet 'Banan': " + frugter); // 3. Opdater et element på et specifikt indeks frugter.add("Pære"); // Listen er nu [Orange, Pære] frugter.set(0, "Kiwi"); // Erstatter "Orange" med "Kiwi" System.out.println("Efter opdatering af indeks 0: " + frugter); // 4. Hent et element String førsteFrugt = frugter.get(0); System.out.println("Den første frugt er nu: " + førsteFrugt); } } Fordele og Ulemper ved ArrayList
Som enhver anden datastruktur har ArrayList sine styrker og svagheder. Det er vigtigt at kende dem for at kunne vælge den rigtige struktur til opgaven.
| Fordele | Ulemper |
|---|---|
|
|
Dybdegående Kig på Generics: Hvorfor virker new ArrayList<T>()?
Et almindeligt forvirringspunkt for udviklere, der er nye inden for generics, er forskellen mellem en typeparameter som <T> og en konkret type som <String>. Man kan læse, at en parametriseret type som ArrayList<T> ikke kan instantieres, fordi T blot er en pladsholder. Hvordan kan følgende kode så kompilere uden fejl?
public static <T> List<T> getList(T... elements) { List<T> lst = new ArrayList<>(); // Hvorfor er dette gyldigt? // ... logik til at tilføje elementer ... return lst; } Svaret ligger i, hvordan Javas generiske system og typeinferens fungerer:
- Typeparameteren
Tdefineres af metoden: Når du skriverpublic static <T>, fortæller du compileren, at denne specifikke metode er generisk. TypenTvil blive bestemt, hver gang metoden kaldes, baseret på de argumenter, der gives. - Kompileringstid vs. Køretid (Type Erasure): Java implementerer generics gennem en proces kaldet "type erasure". Under kompilering kontrollerer compileren, at du bruger typerne korrekt (f.eks. at du ikke tilføjer en
Integertil enList<String>). Men efter kompilering fjernes den generiske typeinformation. Ved køretid ser JVM'en stort set kun enArrayListafObject. - Typeinferens med Diamond Operator (
<>): Siden Java 7 kan du bruge "diamond operator"<>. Når du skrivernew ArrayList<>(), beder du compileren om selv at udlede den generiske type fra konteksten. I eksemplet ovenfor er konteksten, at vi tildeler til en variabel af typenList<T>. Derfor forstår compileren, atnew ArrayList<>()skal værenew ArrayList<T>().
Så selvom du ikke kan skrive new ArrayList<T>() i en klasse, hvor T ikke er defineret, kan du sagtens gøre det inden i en generisk metode eller klasse, hvor T er en kendt typeparameter. Når metoden getList("a", "b") kaldes, vil compileren erstatte T med String for netop det kald, og det er fuldt ud gyldigt.
Ofte Stillede Spørgsmål (FAQ)
Hvornår skal man bruge ArrayList i stedet for et almindeligt array?
Brug en ArrayList, når du ikke kender det præcise antal elementer på forhånd, eller hvis du forventer, at antallet af elementer vil ændre sig ofte. Hvis du har en fast, uforanderlig samling af data, kan et almindeligt array være en smule mere ydeevne-effektivt på grund af mindre overhead.
Hvad er forskellen på ArrayList og LinkedList?
ArrayList er implementeret med et dynamisk array, mens LinkedList er implementeret som en dobbeltkædet liste. Det betyder, at ArrayList er meget hurtigere til at hente elementer via indeks (get()), mens LinkedList er meget hurtigere til at tilføje og fjerne elementer fra starten eller midten af listen. Vælg ArrayList for hyppig læseadgang og LinkedList for hyppige indsættelser/sletninger.
Hvordan itererer man over en ArrayList?
Der er flere måder. De mest almindelige er:
- For-each loop:
for (String s: minListe) { ... }(mest læsevenlige) - Almindeligt for-loop med indeks:
for (int i = 0; i < minListe.size(); i++) { ... }(når du har brug for indekset) - Iterator:
Iterator<String> it = minListe.iterator(); while(it.hasNext()) { ... }(giver mulighed for at fjerne elementer under iteration)
Hvis du vil læse andre artikler, der ligner Forståelse af ArrayList i Java: En Komplet Guide, kan du besøge kategorien Sundhed.
