Volodymyr Portianko
Java Engineer bei Playtika

ArrayList-Klasse

Veröffentlicht in der Gruppe Germany
Hallo! In den vorangegangenen Lektionen haben wir uns eingehend mit Arrays beschäftigt und allgemeine Beispiele für die Arbeit mit Arrays besprochen. ArrayList-Klasse - 1Im Allgemeinen sind Arrays super praktisch. Und wie du schon gemerkt hast, kannst du eine Menge mit ihnen machen :) Aber Arrays haben auch eine Reihe von Mängeln.
  • Begrenzte Größe. Du musst wissen, wie viele Elemente dein Array enthalten soll, wenn du es erstellst. Wenn du die nötige Größe unterschätzt, hast du nicht genug Platz. Wenn du sie überschätzt, bleibt es halbleer, was ebenfalls schlecht ist. Schließlich weist du dann mehr Speicherplatz zu, als nötig ist.
  • Ein Array hat keine Methoden zum Hinzufügen von Elementen. Du musst immer explizit den Index der Position angeben, an der du ein Element hinzufügen möchtest. Wenn du versehentlich den Index für eine Position angibst, die schon mit einem Wert belegt ist, den du brauchst, wird dieser überschrieben.
  • Es gibt keine Methoden, um ein Element zu löschen. Ein Wert kann nur „genullt“ werden.

public class Cat {

   private String name;

   public Cat(String name) {
       this.name = name;
   }

   public static void main(String[] args) {

       Cat[] cats = new Cat[3];
       cats[0] = new Cat("Thomas");
       cats[1] = new Cat("Behemoth");
       cats[2] = new Cat("Lionel Messi");

       cats[1] = null;



       System.out.println(Arrays.toString(cats));
   }

   @Override
   public String toString() {
       return "Cat{" +
               "name='" + name + '\'' +
               '}';
   }
}
Ausgabe:
[Cat{name='Thomas'}, null, Cat{name='Lionel Messi'}]
Glücklicherweise sind sich die Erfinder von Java der Vor- und Nachteile von Arrays bewusst und haben deshalb eine sehr interessante Datenstruktur namens ArrayList geschaffen. Einfach ausgedrückt ist eine ArrayList ein „aufgemotztes“ Array mit einer Menge neuer Funktionen. Es ist sehr einfach zu erstellen:

ArrayList<Cat> cats = new ArrayList<Cat>();
Jetzt haben wir eine Liste zum Speichern von Cat-Objekten erstellt. Beachte, dass wir die Größe der ArrayList nicht angeben, da sie sich automatisch erweitern kann. Wie ist das möglich? Das ist eigentlich ganz einfach. Es mag dich überraschen, aber ArrayList ist auf einem ganz normalen Array aufgebaut :) Ja, es enthält ein Array, in dem unsere Elemente gespeichert werden. Aber ArrayList hat eine besondere Art, mit diesem Array zu arbeiten:
  • Wenn das interne Array gefüllt ist, erstellt ArrayList intern ein neues Array. Die Größe des neuen Arrays ist die Größe des alten Arrays mal 1,5 plus 1.
  • Alle Daten werden aus dem alten Array in das neue Array kopiert
  • Das alte Array wird vom Garbage Collector aufgeräumt.
Dieser Mechanismus ermöglicht es ArrayList (im Gegensatz zu einem gewöhnlichen Array), eine Methode zum Hinzufügen neuer Elemente zu implementieren. Und das ist die add()-Methode:

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<Cat>();
   cats.add(new Cat("Behemoth"));
}
Neue Einträge werden am Ende der Liste hinzugefügt. Jetzt besteht kein Risiko mehr, dass das Array überläuft, also ist diese Methode absolut sicher. Übrigens kann ArrayList ein Objekt nicht nur über seinen Index finden, sondern auch umgekehrt: Es kann eine Referenz verwenden, um den Index eines Objekts in der ArrayListzu finden! Dafür gibt es die Methode indexOf(): Wir übergeben eine Referenz auf das gewünschte Objekt, und indexOf() gibt seinen Index zurück:

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);

   int thomasIndex = cats.indexOf(thomas);
   System.out.println(thomasIndex);
}
Ausgabe:
0
Das ist richtig. Unser thomas-Objekt ist tatsächlich in Element 0 gespeichert. Arrays haben nicht nur Nachteile. Sie haben auch unbestreitbare Vorteile. Eines davon ist die Möglichkeit, Elemente nach seinem Index zu suchen. Da wir auf einen Index zeigen, d. h. auf eine bestimmte Speicheradresse, ist die Suche in einem Array auf diese Weise sehr schnell. ArrayList weiß auch, wie man das macht! Die get()-Methode implementiert genau das:

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);

   Cat secondCat = cats.get(1);

   System.out.println(secondCat);
}
Ausgabe:
Cat{name='Behemoth'}
Außerdem kannst du mit der contains()-Methode ganz leicht herausfinden, ob die ArrayList ein bestimmtes Objekt enthält:

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);

   cats.remove(fluffy);
   System.out.println(cats.contains(fluffy));
}
Die Methode prüft, ob das interne Array der ArrayList das Element enthält, und gibt ein boolean (true oder false) zurück. Ausgabe:
false
Und noch etwas Wichtiges zum Einfügen. Mit ArrayList kannst du einen Index verwenden, um Elemente nicht nur am Ende des Arrays, sondern überall einzufügen. Hierfür gibt es zwei Methoden:
  • add(int index, Cat element)
  • set(int index, Cat element)
ArrayList-Klasse - 2Beide Methoden nehmen als Argumente den Index der Position, an der du etwas einfügen willst, und einen Verweis auf das Objekt selbst entgegen. Der Unterschied ist, dass das Einfügen mit set() den alten Wert überschreibt. Beim Einfügen mit add() werden zunächst alle Elemente von [index] bis zum Ende des Arrays um eins verschoben und dann das angegebene Objekt an der entstandenen leeren Position hinzugefügt. Hier ist ein Beispiel:

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);

   System.out.println(cats.toString());

   cats.set(0, lionel);// Jetzt haben wir eine Liste mit 2 Katzen. Hinzufügen einer 3. Katze mit set

   System.out.println(cats.toString());
}
Ausgabe:
[[Cat{name='Thomas'}, Cat{name='Behemoth'}] [Cat{name='Lionel Messi'}, Cat{name='Behemoth'}]
Wir hatten eine Liste mit 2 Katzen. Dann haben wir mit der set()-Methode eine weitere als Element 0 eingefügt. Dadurch wurde das alte Element durch ein neues ersetzt.

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);

   System.out.println(cats.toString());

   cats.add(0, lionel);// Jetzt haben wir eine Liste mit 2 Katzen. Hinzufügen einer 3. Katze mit add

   System.out.println(cats.toString());
}
Und hier sehen wir, dass add() anders funktioniert. Es verschiebt alle Elemente nach rechts und schreibt dann den neuen Wert als Element 0. Ausgabe:
[Cat{name='Thomas'}, Cat{name='Behemoth'}] [Cat{name='Lionel Messi'}, Cat{name='Thomas'}, Cat{name='Behemoth'}]
Um die Liste vollständig zu leeren, verwenden wir die Methode clear():

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);

   cats.clear();

   System.out.println(cats.toString());
}
Ausgabe:
[]
Alles wurde aus der Liste entfernt. Übrigens: Im Gegensatz zu Arrays überschreibt ArrayList die toString()-Methode und stellt die Liste bereits entsprechend als Zeichenkette dar. Bei normalen Arrays mussten wir dafür die Klasse Arrays verwenden. Und da ich Arrays schon erwähnt habe: In Java kannst du ganz einfach zwischen einem Array und einer ArrayList „umschalten“, d. h. das eine in das andere umwandeln. Die Klasse Arrays hat eine Methode Arrays.asList() für genau diesen Zweck. Wir verwenden sie, um den Inhalt als Array zu erhalten und an unseren ArrayList-Konstruktor zu übergeben:

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();


   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   Cat[] catsArray = {thomas, behemoth, lionel, fluffy};

   ArrayList<Cat> catsList = new ArrayList<>(Arrays.asList(catsArray));
   System.out.println(catsList);
}
Ausgabe:
[Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}]
Du kannst auch in die andere Richtung gehen: ein Array aus einem ArrayList-Objekt erhalten. Das machen wir mit der Methode toArray():

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();

   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);

   Cat[] catsArray = cats.toArray(new Cat[0]);

   System.out.println(Arrays.toString(catsArray));
}
Hinweis: Wir haben ein leeres Array an die Methode toArray() übergeben. Dies ist kein Fehler. In der Klasse ArrayList ist diese Methode so implementiert, dass die Übergabe eines leeren Arrays die Performance erhöht. Behalte das für die Zukunft im Hinterkopf (du kannst natürlich auch ein Array mit einer bestimmten Größe übergeben; das funktioniert auch). Oh, was die Größe angeht. Die aktuelle Größe der Liste kann mit der Methode size() ermittelt werden:

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();


   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);

   System.out.println(cats.size());
}
Es ist wichtig zu wissen, dass die Methode ArrayList.size() im Gegensatz zur Eigenschaft length eines Arrays die tatsächliche Anzahl der Elemente zurückgibt und nicht die ursprüngliche Kapazität. Schließlich haben wir bei der Erstellung der ArrayList keine Größe angegeben. Du kannst sie aber angeben – ArrayList hat einen passenden Konstruktor. Aber wenn du neue Elemente hinzufügst, ändert das nichts an ihrem Verhalten:

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>(2);// erstelle eine ArrayList mit einer anfänglichen Kapazität von 2


   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);

   System.out.println(cats.size());
}
Konsolenausgabe:
4
Wir haben eine Liste mit 2 Elementen erstellt, aber sie hat sich still und leise erweitert, als es nötig war. Eine weitere Überlegung ist, dass wir, wenn wir anfangs eine sehr kleine Liste erstellen, diese öfter erweitern müssen, was einige Ressourcen verbraucht. Wir haben in dieser Lektion kaum über das Entfernen von Elementen aus einer ArrayList gesprochen. Das liegt natürlich nicht daran, dass wir es vergessen hätten. Wir haben dieses Thema in eine separate Lektion gepackt, die du später kennenlernen wirst :)
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION