1. Definition
Array
Arrays gehören zu den Containerobjekten und können eine feste, vorgegebene Zahl von Werten des gleichen Typs speichern.
Containerobjekte sind in Java im weitesten Sinn Objekte, die andere Objekte speichern und verwalten können. Dazu stellen sie bestimmte Methoden bereit, um auf die gespeicherten Objekte zuzugreifen. So können Objekte hinzugefügt, entfernt, gesucht oder verändert werden. Auch das Sortieren der Objekte ist bei manchen Containerobjekten möglich.
Merkmale von Arrays
Arrays sind die einfachsten Containerobjekte. Hier werden keine Methoden zur Verfügung gestellt, für das Hinzufügen und Löschen, das Suchen und Sortieren etc. müssen eigene Methoden entwickelt werden.
Feste Größe:
Die Zahl der Arrayelemente wird bei der Initialisierung festgelegt und kann nicht mehr geändert werden.
int[] zahlen = new int[20];
Dieser Array mit dem Namen "zahlen" kann maximal 20 Elemente des Datentyps int speichern.
Homogener Typ:
Alle Elemente eines Array müssen den gleichen Datentyp besitzen. Dies kann ein primitiver Datentyp wie int oder double sein, es können aber auch Objekte von Klassen gespeichert werden.
Circle[] kreise = new Circle[100];
das Array kreise speicher bis zu 100 Objekte der Klasse Circle.
Indizierter Zugriff:
Die Elemente eines Arrays werden über einen sogenannten Index angesprochen.
kreise[5].changeColor("yellow");
Diese Anweisung ändert die Farbe des sechsten Kreis-Elementes. Das erste Element eines Array hat immer den Index 0, das letzte Element den Index N-1, wenn N die Zahl der Elemente ist.
2. Deklaration und Initialisierung
Der folgende Quelltext zeigt verschiedene Möglichkeiten der Deklaration und Initialisierung von Arrays - alle am Beispiel von int-Arrays:

Text
Autor: Ulrich Helmich 2024, Lizenz: Public domain
Dieses Bild zeigt verschiedene Arten der Deklaration und Initialisierung von int-Arrays.
In der Zeile 3 wird ein int-Array mit dem Namen zahlen deklariert. Die eckigen Klammern befinden sich hinter dem Bezeichner: int zahlen[]; Allerdings ist diese Art der Deklaration ungewöhnlich und recht selten - aber möglich.
In der Zeile 4 finden wir die "klassische" Variante der Deklaration, der eckigen Klammern hinter dem Datentyp int[] werte;
In der Zeile 5 wird das Array primzahlen deklariert, initialisiert und gleichzeitig mit Werten gefüllt, den ersten Primzahlen bis 29. Die Größe des Arrays wird hier automatisch durch die Anzahl der in den Klammern {} stehenden Elemente bestimmt. Diese letzte Variante ist eine sehr bequeme Art, kleinere Arrays in "einem Rutsch" zu deklarieren, zu initialisieren und mit Werten zu befüllen.
2.1 Initialisierung mit for-Schleifen
Diese Methode kennen Sie wahrscheinlich noch aus dem Informatik-Unterricht der Schule. Hier ein Beispiel:
int[] quadratZahlen = new int[10]; for (int i = 0; i < quadratZahlen.length; i++)
quadratZahlen[i] = i * i;
2.2 Methoden der Klasse Arrays
2.2.1 Die Arrays.fill()-Methode
Die Klasse Arrays, die Java zur Verfügung stellt, bietet viele Methoden zum Umgang mit Arrays an. Zum Befüllen von Arrays wird die Methode fill() zur Verfügung gestellt. Diese Methode füllt ein Array mit gleichen Werten:
import java.util.Arrays; ... int[] zahlen = new int[5]; Arrays.fill(zahlen, 9);
Die Klasse Arrays aus der Java-Bibliothek java.util muss erst noch importiert werden, das geschieht hier in der ersten Zeile. In der zweiten Zeile wird ein int-Array mit fünf Elementen deklariert und initialisiert, und in der letzten Zeile wird jedem der fünf Arrayelement der Wert 9 zugewiesen.
Die Methode Arrays.fill() ist sehr nützlich, wenn man einen großen Array mit einem bestimmten Initialwert befüllen will, ohne eine for-Schleife schreiben zu müssen.
2.2.2 Die Arrays.copyOf()-Methode
Wenn man die Inhalte eines Arrays in einen zweiten Array gleichen Typs kopieren will, kann man das mit einer for-Schleife machen, oder man benutzt die Methode copyOf() der Klasse Arrays:
int[] original = {1, 2, 3}; int[] kopie = Arrays.copyOf(original, 5);
Die drei Zahlen des ersten Arrays werden in die drei ersten Elemente des zweiten Arrays hineinkopiert. Da der Parameter 5 in der copyOf()-Methode die Länge des zweiten Arrays aber auf 5 festgelegt hat, erhalten die beiden letzten Arrayelemente des zweiten Arrays die Werte 0.
In diesem Lexikon-Artikel finden Sie grundlegende Informationen zu diesem Thema. An sich für Schüler(innen) der gymnasialen Oberstufe geschrieben, aber auch durchaus hilfreich für Leute, die gerade mit dem Informatik-Studium angefangen sind.
Ein zweiter hilfreiche Lexikon-Artikel. Hier wird auch ausführlich auf Objekt-Arrays eingegangen und auf die Speicherverwaltung bei der Deklaration und Initialisierung eines Objekt-Arrays.
3. Zugriff auf die Arrayelemente
Ein Array ist ein Datenfeld fester Länge, das mehrere Werte desselben Typs speichert. Der Zugriff erfolgt über numerische Indizes, die bei 0 beginnen und bis array.length - 1 reichen.
3.1 Zugriff auf ein einzelnes Element
Um ein bestimmtes Element anzusprechen, schreibt man den Namen des Arrays und in eckigen Klammern den gewünschten Index:
int[] zahlen = { 4, 7, 2, 9, 5 };
int erstes = zahlen[0];
int letztes = zahlen[4];
Achtung: Ein Zugriff auf einen ungültigen Index wie zahlen[5] löst eine ArrayIndexOutOfBoundsException aus.
3.2 Zugriff auf alle Elemente
Um alle Arrayelemente nacheinander zu verarbeiten, verwendet man Schleifen, meistens werden dabei for-Schleifen bevorzugt, weil die Zahl das Arrayelemente ja von "for-nherein" bekannt ist.
3.2.1 for-Schleife mit Index
for (int i = 0; i < zahlen.length; i++) { System.out.println(zahlen[i]); }
Das ist wohl die bekannteste Variante, die alle Elemente des Arrays nacheinander ausgibt. Natürlich kann man mit Hilfe von eingebauten if-else-Bedingungen diese Ausgabe beeinflussen:
for (int i = 0; i < zahlen.length; i++) { if (i%2 == 0) System.out.println(zahlen[i]); }
Hier werden nur die geraden Zahlen des Arrays ausgegeben.
3.2.2 for-each-Schleife
for (int zahl : zahlen) { System.out.println(zahl); }
Die for-each-Schleife- (auch erweiterte for-Schleife genannt) durchläuft automatisch alle Elemente in der Reihenfolge ihrer Speicherung. Der Index ist dabei nicht direkt zugänglich.
Merke:
Zugriff auf Arrayelemente
- Einzelzugriff erfolgt über array[index].
- Für vollständige Durchläufe nutzt man for- oder for-each-Schleifen.
- Die kleinste gültige Indexposition ist 0, die größte array.length - 1.
4. Zweidimensionale Arrays
Während es in Programmiersprachen wie Pascal "echte" zweidimensionale Arrays gibt, kann man in Java einen zweidimensionalen Array nachbilden, indem man ein Array deklariert, dessen Elemente ebenfalls Arrays sind. Diese Arrays im Array müssen natürlich alle den gleichen Elemententyp haben.
4.1 Deklaration, Initialisierung und Zugriff
Hier ein einfaches Beispiel für ein Array, dessen Elemente Arrays aus int-Zahlen sind:
public class MatrixDemo { private int[][] matrix; public MatrixDemo() { matrix = new int[3][3]; } public void befuelle() for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) matrix[i][j] = (i + 1) * (j + 1); } public void ausgeben() { System.out.println("Inhalt der 3x3-Matrix:"); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) System.out.printf("%4d", matrix[i][j]); System.out.println(); } } }
Bei der Deklaration schreiben Sie hinter den Typenbezeichner (zum Beispiel int) zwei Paar eckiger Klammern:
private int[][] matrix;
Bei der Initialisierung müssen Sie angeben, wie viele Arrays das Array enthalten soll, und wie groß diese Arrays sein sollen:
matrix = new int[3][3];
das Array matrix enthält drei Elemente, und jedes Element ist ein int-Array mit seinerseits drei Elementen.
Um einen solchen zweidimensionalen Array mit Werten zu füllen, empfehlen sich zweifach geschachtelte for-Schleifen - zur Ausgabe oder Auswertung eines solchen Arrays kommen dann ebenfalls solche for-Schleifen zum Einsatz.
4.2 Anwendungsbeispiele für zweidimensionale Arrays
Immer dann, wenn eine zweidimensionale Tabelle dargestellt werden soll, zum Beispiel wenn die Noten von Schüler(innen) einer Klasse gespeichert werden sollen:
Nr. | Name | Deutsch | Englisch | Chemie | Biologie | Informatik |
---|---|---|---|---|---|---|
1 | Müller, Anna | 2 | 3 | 2 | 1 | 1 |
2 | Schmidt, Ben | 3 | 2 | 3 | 3 | 2 |
3 | Meier, Clara | 1 | 1 | 2 | 2 | 1 |
4 | Weber, David | 4 | 3 | 4 | 3 | 2 |
5 | Fischer, Emma | 2 | 1 | 2 | 2 | 1 |
6 | Wagner, Felix | 3 | 4 | 3 | 3 | 2 |
7 | Becker, Greta | 1 | 2 | 1 | 1 | 1 |
8 | Hoffmann, Jonas | 4 | 3 | 4 | 4 | 3 |
9 | Schäfer, Lara | 2 | 2 | 2 | 2 | 1 |
10 | Koch, Max | 3 | 3 | 4 | 3 | 2 |
11 | Bauer, Nina | 2 | 1 | 2 | 1 | 1 |
12 | Klein, Oliver | 4 | 4 | 3 | 4 | 2 |
Die Tabelle habe ich mir übrigens von ChatGPT generieren lassen, die Namen habe ich mir also nicht ausgedacht, die Fächer dagegen habe ich vorgeschlagen.
Wenn in einem Spiel ein Spielfeld dargestellt werden soll, zum Beispiel in einem Dame- oder Schachspiel. Ich bin ja mal gespannt, was ChatGPT mir jetzt erzeugt...
a | b | c | d | e | f | g | h | |
---|---|---|---|---|---|---|---|---|
8 | sT | sK | sS | |||||
7 | sB | sB | sL | sB | sB | |||
6 | wS | sL | ||||||
5 | wB | wB | wB | |||||
4 | wS | wL | ||||||
3 | wB | wB | wB | |||||
2 | wB | wD | wL | |||||
1 | wT | wS | wK | wT |
Die Kürzel stehen für die einzelnen Spielfiguren eines Schachspiels. "wB" ist zum Beispiel ein weißer Bauer, während "sK" für den schwarzen König steht.
Wenn bei der Bildverarbeitung ein Bild Pixel für Pixel analysiert werden soll, so kann man das Bild oder Ausschnitte aus dem Bild in einem zweidimensionalen Array speichern - zumindest wenn es sich um ein Schwarzweiß-Bild handelt.
Bei einem farbigen RGB-Bild wird die Sache komplizierter. Der zweidimensionale Array ist vielleicht 1600 x 1200 Pixel groß, aber jeder Pixel wiederum besteht aus drei Komponenten, nämlich dem Rot-Anteil, dem Grün-Anteil und dem Blau-Anteil. Im Grunde haben wir es hier schon mit einem dreidimensionalen Array zu tun.
4.3 Dreidimensionale Arrays
Die Deklaration und Initialisierung eines solchen dreidimensionalen Arrays könnte so aussehen:
int[][][] pixel; pixel = new int[1600][1200][3];
Die oben bereits erwähnte Notenliste könnte um eine dritte Dimension erweitert werden, wenn zum Beispiel die zeitliche Entwicklung der einzelnen Noten dokumentiert werden soll:
Für jeden Schüler und jedes Fach die erste mündliche Note, die erste Klausurnote, die zweite mündliche Note und die zweite Klausurnote, das wäre dann ein Array aus vier int-Zahlen, der als Element des zweidimensionalen Arrays auftritt:
int noten[][][];
noten = new int[12][5][4];
das Array ist also für 12 Schüler(innen), 5 Fächer und 4 Noten pro Fach geeignet.
5. Typische Fehler beim Umgang mit Arrays
Bei der Arbeit mit Arrays kommt es gerade am Anfang leicht zu typischen Fehlern. Die folgenden Beispiele zeigen häufige Probleme und wie man sie vermeiden kann.
5.1 IndexOutOfBoundsException
Java-Arrays beginnen immer mit dem Index 0. Der letzte gültige Index ist array.length - 1.
Hier ein einfaches Beispiel:
public class FehlerBeispiel1 { private int[] zahlen = {10, 20, 30}; public void testZugriff() System.out.println(zahlen[3]); }
Es soll die dritte Zahl des Array ausgegeben werden, diese hat aber nicht den Index 3, sondern den Index 2!
Oft treten solche Fehler auf, wenn eine for-Schleife den Array ausgeben oder auswerten soll:
public class FehlerBeispiel2 { private int[] zahlen = {1, 2, 3, 4, 5}; public void ausgeben() { for (int i = 0; i <= zahlen.length; i++) System.out.println(zahlen[i]); } }
Hier wurde bei der Formulierung der Abbruchbedingung in der for-Schleife nicht aufgepasst. Der Wert von zahlen.length ist 5, das letzte Arrayelement hat aber den Index 4. Es hätte also heißen müssen: i < zahlen.length und nicht i <= zahlen.length.
5.2 NullPointerException bei Arrays von Objekten
Ein Array von Objekten enthält nach der Initialisierung nur null-Referenzen, keine fertigen Objekte.
public class FehlerBeispiel3 { private String[] namen = new String[3]; public void testLaenge() { System.out.println(namen[0].length()); } }
das Array wurde zwar korrekt deklariert und initialisiert, aber in dem Arrayelement mit dem Index 0 ist noch keine Referenz auf ein existierendes Objekt eingetragen, sondern nur der Wert null. Während die Adresse eines Objekts mit dem System.out.println()-Befehl ausgegeben werden kann (in völlig kryptischer Form allerdings), streikt der Befehl bei der Ausgabe eines null-Wertes.
Hätte man vor dem println()-Befehl folgende Zeile hinzgefüt:
namen[0] = "Otto";
dann würde tatsächlich "Otto" ausgegeben.
Einen solchen Fehler kann man aber auch bei einfachen Arrays machen. Schauen Sie sich dazu folgendes Code-Beispiel an:
int[] zahlen; ... zahlen[0] = 5;
das Array wurde zwar deklariert, aber noch nicht initialisiert. Daher existiert das Element zahlen[0] noch gar nicht und die Zuweisung führt zu einem Laufzeitfehler.
Das "Gemeine" an diesem Fehler ist, dass der Compiler ihn noch nicht bemerkt - zumindest bei BlueJ wird ein Quelltext mit einem solchen Fehler problemlos übersetzt. Erst wenn man die Methode mit diesem Fehler ausführen möchte, kommt eine lange Fehlermeldung: "java.lang.NullPointerException: Cannot store to int array because 'this.fehler' is null".
5.3 Verwechslung von Indizes bei 2D-Arrays
Ein Fehler, die selbst erfahrenen Entwicklern oft passiert, ist die Verwechslung der Zeilen und Spalten in einem zweidimensionalen Array. Als mathematisch geprägter Mensch ist man immer geneigt, bei den Positionsangaben von Objekten zuerst die x-Koordinate und dann die y-Koordinate anzugeben: (x,y).
Bei Tabellen ist es aber genau umgekehrt. Man gibt zuerst die Zeilennummer an, und dann die Spaltennummer - also erst die y-Koordinate, und dann die x-Koordinate.
Klar, dass das dann oft zu Fehlern im Umgang mit 2D-Arrays führt.
Im folgenden Beispiel enthält das Array zwei Zeilen mit jeweils drei Spalten:
public class FehlerBeispiel4 { private int[][] matrix = { {1, 2, 3}, // Zeile 0 {4, 5, 6} // Zeile 1 }; public void testZugriff() { System.out.println(matrix[0][2]); System.out.println(matrix[1][0]); } }
Ein Fehler wäre es beispielsweise, wenn man matrix[2][0] ausgeben wollte. Das hieße nämlich, dass man auf die dritte Zeile der Matrix zugreifen wollte. Es gibt aber nur zwei Zeilen, und der Index der zweiten Zeile ist 1. Der Index 2 ist also ungültig und würde zu einem Laufzeitfehler führen.
5.4 Falsche Arraygröße
Manchmal wird ein Array mit einer Größe initialisiert, die nicht ausreicht, um alle benötigten Elemente zu speichern, oder die zu groß ist und somit Speicherplatz verschwendet.
5.5 Verwechseln von Array-Referenzen
Wenn Sie ein Array A einer anderen Array-Variablen B zuweisen, kopieren Sie nicht die Inhalte des Arrays A, sondern lediglich die Adresse von A. Die Arrayvariable B zeigt dann auf den selben Speicherbereich wie die Arrayvariable A.
int[] arrayA = {1, 4, 7, 12}; int[] arrayB = {3, 5, 8}; ... arrayB = arrayA; arrayB[0] = 2; System.out.println(arrayA[0]);
Was wird hier passieren?
Obwohl das erste Element von ArrayA den Wert 1 hatte, wird die Zahl 2 ausgegeben.
Durch die Zuweisung arrayB = arrayA
wird jetzt in arrayB die gleiche Adresse gespeichert wie in arrayA. Wenn also arrayB[0] geändert wird, wirkt sich das auch auf arrayA[0] aus, den beide Arrayvariablen zeigen auf den gleichen Speicherbereich.
Dieses Phänomen wird als "flache Kopie" oder shallow copy bezeichnet.
Wenn Sie eine unabhängige Kopie eines Arrays erstellen möchten, die von Änderungen am Original nicht betroffen ist, müssen Sie eine "tiefe Kopie" oder deep copy durchführen. Das bedeutet, Sie erstellen einen neuen Array und kopieren die Elemente einzeln. Das würde am besten mit einer for- oder einer for-each-Schleife gehen. Aber auch die Java-Klasse Arrays stellt einige Methoden dafür zur Verfügung.
5.6 Verwechslung von Länge und Kapazität
Manchmal wird die Größe eines Arrays (die Anzahl der tatsächlich enthaltenen Elemente) mit seiner Länge (der maximalen Anzahl von Elementen, die es speichern kann) verwechselt. Dies ist besonders relevant, wenn man mit teilweise gefüllten Arrays arbeitet oder wenn man eine Datenstruktur (wie einen Stack) mit einem Array als zugrunde liegendem Speicher implementiert.
Im Oberstufenunterricht wird der Abstrakte Datentyp Stack häufig mit einem Array implementiert. Der Stack ist aber ein dynamischer Datentyp, seine Länge ist variabel und vor dem Übersetzen des Codes nicht bekannt. Daher nimmt man oft ein Array der Länge 100, 200 oder mehr. Wenn man aber nur fünf Stack-Elemente in dem Array gespeichert hat, die die effektive Größe des Arrays 5, während seine Länge 100, 200 oder mehr ist.
Wenn Sie jetzt also Code schreiben wie zum Beispiel
int[] stack; stack = new int[100]; int groesse = 0; ... stack[0] = 2; stack[1] = 6; stack[2] = 4; groesse = 3; ... for (int i=0; i < stack.length; i++) System.out.println(stack[i]);
dann erhalten Sie nicht die gewünschte Ausgabe, sondern der ganze Array wird ausgegeben. Bei einem int-Array würden dann die ersten drei Zahlen erscheinen, also 2, 6 und 4, und dann nur noch Nullen. Bei einem Objekt-Array würde dagegen das Element stack[2] noch ausgegeben, bei stack[3] würde aber ein Laufzeitfehler auftreten, da stack[3] und die folgenden Elemente noch keine brauchbare Adresse enthalten, sondern nur den Wert null.
Arrays als Parameter von Methoden
Man kann Arrays als Instanzvariablen von Klassen verwenden, so dass alle Methoden auf diesen Array zugreifen können.
Manchmal will man aber auch einfach eine unabhängige und universell einsetzbare Methode schreiben, die eine Operation auf einen beliebigen int- oder double-Array ausführt (oder auf Arrays mit anderen Elementtypen). Wenn eine solche Methode wirklich unabhängig von einer bestimmten Klasse sein soll, darf man innerhalb der Methode nicht auf ein Array mit einem konkreten Namen zugreifen. Die Methode weiß ja noch gar nicht, wie das Array heißt, den sie bearbeiten oder auswerten soll. Außerdem soll die Methode auf viele verschiedene Arrays mit unterschiedlichen Namen zugreifen können. Erst dann ist die Methode universell als Werkzeug einsetzbar. Betrachten wir einmal am Beispiel einer Suche nach der kleinsten Zahl, wie eine solche universelle Methode aufgebaut sein könnte:.
public int mini(int[] zahlen) { int mini = zahlen[0]; for (int i=1; i < zahlen.length; i++) if (zahlen[i] < mini) mini = zahlen[i]; return mini; }
Der Kopf der Methode
public int mini(int[] zahlen)
hat einen formalen Parameter von Typ int[] namens zahlen, erwartet also beim Aufruf einen aktuellen Parameter ebenfalls vom Typ int[], dessen Name aber völlig egal ist.
Angenommen, wir haben in der Klasse oder in einer anderen Methode ein Array namens hundertZahlen deklariert und initialisiert und außerdem noch mit Zahlen gefüllt, dann können wir diese neue Methode wie folgt aufrufen:
int m = mini(hundertZahlen)
das Array hundertZahlen wird also als aktueller Parameter an die Methode übergeben. Die gefundene kleinste Zahl wird dann an die lokale Variable m überwiesen.
Quellen:
- Lahres et al.: Objektorientierte Programmierung, Rheinwerk Computing 2021.
- Barnes, Kölling: Java lernen mit BlueJ - Objects first. Pearson-Verlag 2019.
- Ullenboom: Java ist auch eine Insel, Rheinwerk Computing 2023.