Zum Inhalt springen

Arrays in Java deklarieren und initialisieren

Eine liegende Glasschale mit einer Reihe von Fächern vor Seegrün; in den linken vier liegt je eine leuchtende Murmel in Bernstein, Rot, Gelb und Grün, über den drei leeren Fächern rechts fallen eine violette, eine orange und eine rosa Murmel hinein, die linke schon knapp über dem Rand

In diesem Artikel lernst du verschiedene Möglichkeiten kennen,

  • wie man in Java Arrays deklariert und initialisiert,
  • wie man sie mit Werten füllt,
  • wie man sie kopiert
  • und wie man Collections und Streams in Arrays umwandelt.

Außerdem erfährst du, was die Besonderheiten bei mehrdimensionalen Arrays in Java sind.

Arrays in Java deklarieren und initialisieren

Wir beginnen mit den wohl häufigsten Operationen, der Array-Deklaration und der Array-Initialisierung.

Arrays in Java deklarieren

Die Deklaration einer Variable ist der Zeitpunkt, zu dem wir die Variable zusammen mit ihrem Typ dem Compiler bekanntmachen. Die folgenden zwei Zeilen zeigen die Deklaration eines int-Arrays und eines String-Arrays:

int[] intArray;
String[] stringArray;

Bei der Deklaration geben wir noch nicht die Größe des Arrays an. Die Array-Variablen (im Beispiel intArray und stringArray) enthalten nicht das Array selbst, sondern eine Referenz auf ein Array, das letztendlich ein Objekt auf dem Java-Heap ist. Erst wenn wir das Array-Objekt selbst erzeugen, müssen wir die Größe festlegen.

Bei der Array-Deklaration dürfen die eckigen Klammern auch nach dem Variablennamen stehen:

int intArray[];
String stringArray[];

Dieser Stil wurde aus der Programmiersprache C übernommen. Die gängigen Java-Style-Guides präferieren jedoch den zuerst gezeigten Stil, also mit den Klammern nach dem Typ und vor dem Namen.

Java-Array mit Werten initialisieren

Wir können ein Array bei der Deklaration auch gleich mit Werten initialisieren. Die folgende Code-Zeile zeigt, wie wir ein int-Array initialisieren können:

int[] winningNumbers = new int[]{14, 17, 29, 32, 45, 1, 2};

Und so können wir z. B. ein String-Array initialisieren:

String[] fruits = new String[]{"cherry", "papaya", "huckleberry"};

Da in den vorangegangenen zwei Beispielen der Variablentyp (int bzw. String) in der Zuweisung wiederholt wird, können wir den vorangestellten Typ seit Java 10 auch durch var ersetzen:

var winningNumbers = new int[]{14, 17, 29, 32, 45, 1, 2};
var fruits = new String[]{"cherry", "papaya", "huckleberry"};

Alternativ dürfen wir auch das Keyword new und die zweite Typangabe weglassen, dann muss allerdings die erste Typangabe stehen bleiben und darf nicht durch var ersetzt werden:

int[] winningNumbers = {14, 17, 29, 32, 45, 1, 2};
String[] fruits = {"cherry", "papaya", "huckleberry"};

Auch bei der kombinierten Deklaration und Initialisierung dürfen im C-Stil die eckigen Klammern nach dem Variablennamen stehen:

int winningNumbers[] = {14, 17, 29, 32, 45, 1, 2};
String fruits[] = {"cherry", "papaya", "huckleberry"};

Array-Deklaration und -Initialisierung separieren

Die Erzeugung eines Arrays mit Festlegung aller Array-Elemente kann auch jederzeit nach der Deklaration erfolgen.

int[] winningNumbers;
// . . .
winningNumbers = new int[]{14, 17, 29, 32, 45, 1, 2};

String[] fruits;
// . . .
fruits = new String[]{"cherry", "papaya", "huckleberry"};

Das ist allerdings nur mit dem Keyword new möglich. Die Variante ohne new ist nur bei der im vorherigen Abschnitt gezeigten kombinierten Deklaration und Initialisierung zulässig.

Leeres Array initialisieren

Bei allen bisherigen Beispielen haben wir konkrete Werte vorgegeben, die das Array enthalten soll.

Statt ein Array mit konkreten Werten zu definieren, können wir ein Array auch zunächst nur mit der Angabe seiner Array-Länge initialisieren, so z. B. ein Array mit zehn int-Elementen:

int[] intArray = new int[10];

Die Anweisung new int[10] erzeugt ein neues int-Array mit zehn Elementen. Alle Elemente werden dabei auf den Default-Wert 0 gesetzt. Die Anweisung hat damit denselben Effekt wie die folgende:

int[] intArray = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

Auch diese Art der Initialisierung könnten wir von der Deklaration trennen:

int[] intArray;
// . . .
intArray = new int[10];

Die verschiedenen Array-Typen haben folgende Default-Werte:

  • Für die Ganzzahlen byte, short, int und long ist der Default-Wert 0.
  • Für die Gleitkommazahlen float und double ist der Default-Wert 0,0.
  • Für char ist der Default-Wert das Unicode-Zeichen „NULL“ (U+0000).
  • Für boolean ist der Default-Wert false.
  • Und für alle Objekt-Arrays ist der Default null.

Array mit Werten füllen

Nachdem wir ein Array erzeugt haben (egal auf welche der zuvor gezeigten Arten), können wir es mit Werten füllen. Dazu gibt es verschiedene Möglichkeiten.

Einzelne Array-Elemente setzen

Wenn wir beispielsweise ein int-Array angelegt haben, können wir es Element für Element befüllen, z. B. mit dem Quadrat des jeweiligen Indexes:

int[] intArray = new int[11];
for (int i = 0; i < intArray.length; i++) {
  intArray[i] = i * i;
}

Dieses Array hat dann den folgenden Inhalt:

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Alle Array-Elemente auf den gleichen Wert setzen: Arrays.fill()

Über die Arrays.fill()-Methode können wir ein Array mit einheitlichen Werten füllen. Der folgende Code setzt jedes Element des Arrays auf 99:

int[] intArray = new int[10];
Arrays.fill(intArray, 99);

Dieses Array sieht dann wie folgt aus:

[99, 99, 99, 99, 99, 99, 99, 99, 99, 99]

Es gibt noch eine zweite, überladene fill()-Methode mit zusätzlichen Parametern, über die man den zu füllenden Bereich festlegen kann. Der folgende Code z. B. füllt die ersten fünf Felder mit der 11 und die letzten fünf Felder mit der 77:

int[] intArray = new int[10];
Arrays.fill(intArray, 0, 5, 11);
Arrays.fill(intArray, 5, 10, 77);

Dieses Array sieht dann wie folgt aus:

[11, 11, 11, 11, 11, 77, 77, 77, 77, 77]

Array mit berechneten Werten füllen: Arrays.setAll()

Im Abschnitt „Einzelne Array-Elemente setzen“ habe ich dir Code gezeigt, der ein Array mittels einer Schleife mit Quadratzahlen befüllt.

Das können wir auch einfacher programmieren, und zwar mit der Methode Arrays.setAll(). Dieser Methode übergeben wir das Array sowie eine Lambda-Funktion, die den Wert eines Feldes anhand seines Indexes berechnet:

int[] intArray = new int[11];
Arrays.setAll(intArray, i -> i * i);

Die Verwendung von setAll() macht es einfach, die Verarbeitung zu parallelisieren. Wir müssen dazu lediglich setAll() durch parallelSetAll() ersetzen:

int[] intArray = new int[11];
Arrays.parallelSetAll(intArray, i -> i * i);

Intern verwendet die Methode einen parallelen Stream und damit den gemeinsamen ForkJoinPool. Da die Berechnungsmethode zustandslos ist, kann die Performance bei großen Arrays und teuren Berechnungen nahezu linear mit der Anzahl der CPU-Kerne skalieren – für elf Quadratzahlen lohnt sich der Overhead des Thread-Pools nicht.

Java-Array kopieren

Es gibt verschiedene Methoden in Java, um ein bestehendes Array zu kopieren.

Primitive Arrays kopieren mit clone()

Die einfachste Art, ein Array zu kopieren, ist die clone()-Methode:

int[] intArray = {6, 11, 5, 7, 44, 7, 4};
int[] copy = intArray.clone();

Dadurch entsteht ein zweites Array, das unabhängig vom ersten Array verändert werden kann. Wir können jetzt Werte in beiden Arrays ändern:

intArray[1] = 999;
copy[2] = 88;

Das führt dazu, dass beide Arrays einen unterschiedlichen Inhalt haben:

intArray: [6, 999, 5, 7, 44, 7, 4]
copy:     [6, 11, 88, 7, 44, 7, 4]

Grafisch kannst du dir das wie folgt vorstellen:

Java-Array „intArray“ und das geklonte Array „copy“

Anders sieht es bei Objekt-Arrays aus …

Objekt-Arrays kopieren mit clone()

Wenn wir mit einem Objekt-Array arbeiten, müssen wir beachten, dass nur die Referenzen auf die Objekte kopiert werden, nicht die Objekte selbst.

Im folgenden Beispiel kopieren wir ein Array von StringBuilder-Objekten, ändern dann den Inhalt eines StringBuilder-Objekts im ersten Array und geben beide Arrays aus:

StringBuilder[] fruits = {
  new StringBuilder("cherry"),
  new StringBuilder("papaya"),
  new StringBuilder("huckleberry")
};

StringBuilder[] copy = fruits.clone();

fruits[1].reverse();

System.out.println("fruits: " + Arrays.toString(fruits));
System.out.println("copy:   " + Arrays.toString(copy));

In der Ausgabe wirst du das umgekehrte Wort „ayapap“ an der mittleren Position in beiden Arrays sehen. Das liegt daran, dass nicht das StringBuilder-Objekt kopiert wurde, sondern nur die Referenz darauf. D. h. beide Arrays enthalten eine Referenz auf ein und dasselbe StringBuilder-Objekt:

Java-Array „fruits“ und das geklonte Array „copy“

Wenn du ein Objekt in nur einem Array ändern möchtest, dann musst du es ersetzen, indem du ein neues Objekt, z. B. einen neuen StringBuilder, zuweist. Hängen wir einmal die folgenden Zeilen an den Code von oben an:

copy[2] = new StringBuilder("tomato");

System.out.println("fruits: " + Arrays.toString(fruits));
System.out.println("copy:   " + Arrays.toString(copy));

Dann wirst du folgende Ausgabe sehen – tomato befindet sich nun ausschließlich im geklonten Array:

fruits: [cherry, ayapap, huckleberry]
copy:   [cherry, ayapap, tomato]

Grafisch kannst du dir das wie folgt vorstellen:

Java-Array „fruits“ und das geklonte und modifizierte Array „copy“

Die StringBuilder mit den Inhalten „cherry“ und „ayapap“ sind von beiden Arrays referenziert, der StringBuilder mit dem Inhalt „huckleberry“ ist nur vom fruits-Array referenziert, und der StringBuilder mit dem Inhalt „tomato“ ist nur vom copy-Array referenziert.

System.arraycopy()

Manchmal wollen wir nicht das komplette Array kopieren, sondern nur einen Teil davon. Dafür können wir die Low-Level-Methode System.arraycopy() zu Hilfe nehmen.

Nehmen wir an, wir wollen die mittleren drei Gewinnzahlen in ein anderes Array kopieren. Dann erzeugen wir zuerst ein Ziel-Array der Größe drei:

int[] winningNumbers = {14, 17, 29, 32, 45, 1, 2};
int[] middleThree = new int[3];

Und dann rufen wir wie folgt System.arraycopy() auf und geben das Ergebnis aus:

System.arraycopy(winningNumbers, 2, middleThree, 0, 3);

Die Methode hat die folgenden Parameter:

  1. Quell-Array
  2. Start-Position im Quell-Array
  3. Ziel-Array
  4. Start-Position im Ziel-Array
  5. Anzahl der zu kopierenden Elemente

Die folgende Grafik zeigt noch einmal die Bedeutungen der Parameter:

Java System.arraycopy()

Wir können nun das Ergebnis des Kopiervorgangs ausgeben:

System.out.println("middleThree: " + Arrays.toString(middleThree));

Und wir sollten, passend zur Grafik oben, die folgende Ausgabe sehen:

middleThree: [29, 32, 45]

Arrays.copyOf()

Der Umgang mit System.arraycopy() ist mühsam. Daher gibt es in der Klasse java.util.Arrays einige Hilfsmethoden, die das Kopieren erleichtern.

Mit der Methode Arrays.copyOf() können wir das komplette Array oder Teile des Arrays kopieren. Der folgende Code kopiert das vollständige Array:

int[] winningNumbers = {14, 17, 29, 32, 45, 1, 2};
int[] copy = Arrays.copyOf(winningNumbers, winningNumbers.length);
System.out.println("copy = " + Arrays.toString(copy));

Der zweite Parameter gibt dabei die gewünschte Länge des Ziel-Arrays an. Wenn du dir den Quellcode der Methode Arrays.copyOf() anschaust, wirst du sehen, dass diese einfach clone() aufruft, wenn der zweite Parameter der Länge des Quell-Arrays gleicht.

Wenn du als zweiten Parameter eine kürzere Länge angibst, ist die Kopie entsprechend kürzer als das Original:

int[] firstThree = Arrays.copyOf(winningNumbers, 3);
System.out.println("firstThree = " + Arrays.toString(firstThree));

Dieser Code gibt folgendes aus – das Ziel-Array enthält also die ersten drei Zahlen des Quell-Arrays:

firstThree = [14, 17, 29]

Im Quellcode von Arrays.copyOf() wirst du sehen, dass in diesem Fall zunächst ein neues Array der gewünschten Größe erzeugt wird und dann mit System.arraycopy() die gewünschten Elemente aus dem Quell-Array in das Ziel-Array kopiert werden.

Du kannst auch einen Wert angeben, der größer ist als die Länge des Quell-Arrays:

int[] longerArray = Arrays.copyOf(winningNumbers, 10);
System.out.println("longerArray = " + Arrays.toString(longerArray));

In diesem Fall werden die restlichen Felder des Ziel-Arrays mit Default-Werten (also Nullen) aufgefüllt sein, und du erhältst folgendes Ergebnis:

longerArray = [14, 17, 29, 32, 45, 1, 2, 0, 0, 0]

Arrays.copyOfRange()

Um einen weiter hinten liegenden Teil aus dem Array zu kopieren, können wir Arrays.copyOfRange() verwenden. Der folgende Code kopiert die mittleren drei Elemente, so wie wir es oben mit System.arraycopy() gemacht haben:

int[] winningNumbers = {14, 17, 29, 32, 45, 1, 2};
int[] middleThree = Arrays.copyOfRange(winningNumbers, 2, 5);
System.out.println("middleThree = " + Arrays.toString(middleThree));

Als Parameter gibst du neben dem Quell-Array die Start- und End-Position (nicht die Länge!) des zu kopierenden Bereichs an.

Wenn du in den Quellcode von copyOfRange() schaust, wirst du feststellen, dass auch diese Methode auf clone() und System.arraycopy() zurückgreift.

Arrays aus anderen Datenstrukturen erzeugen

Falls du Daten in einer Collection wie einer Liste oder einem Set hast, kannst du diese mit der toArray()-Methode in ein Array kopieren.

Liste in Array konvertieren: List.toArray()

Das folgende Beispiel zeigt vier Wege, wie du eine String-Liste in ein String-Array konvertieren kannst:

List<String> fruits = List.of("honeydew", "dragonfruit", "boysenberry");
Object[] array1 = fruits.toArray();
String[] array2 = fruits.toArray(new String[fruits.size()]);
String[] array3 = fruits.toArray(new String[0]);
String[] array4 = fruits.toArray(String[]::new);

Die vier Varianten unterscheiden sich darin, welchen Typ sie zurückliefern und wer das Ziel-Array anlegt:

VarianteRückgabetypWer legt das Ziel-Array an?Bewertung
1: toArray()Object[]die Collectionam schnellsten – liefert aber kein String[]
2: toArray(new String[size])String[]wir, in passender Größelangsamer als 3 und 4; anfällig bei nebenläufigen Änderungen
3: toArray(new String[0])String[]die Collection – unser leeres Array gibt nur den Typ vorschnell
4: toArray(String[]::new)String[]die Collection – über den übergebenen Konstruktorschnell; meine Empfehlung

Warum liefert die erste Variante nur ein Object-Array? Weil Collections wie Listen und Sets zur Laufzeit aufgrund der sogenannten Type Erasure keine Typinformationen enthalten – aus Sicht der JVM können sie beliebige Objekte enthalten. Den Zieltyp müssen wir daher selbst mitgeben: als Array – dieses enthält zur Laufzeit seine Typinformation (Varianten 2 und 3) – oder als Konstruktor-Referenz (Variante 4).

Bei der zweiten Variante kopiert toArray() die Elemente der Liste in das von uns übergebene Array. Bei der dritten Variante ist das übergebene Array der Länge 0 nur eine Typvorlage: toArray() erzeugt selbst ein neues Array der benötigten Größe und kopiert die Elemente dorthin.

Die vierte Variante gibt es seit Java 11. Die Collection.toArray()-Methode ruft den übergebenen Konstruktor mit dem Parameter 0 auf, erzeugt also ein Array der Länge 0 und ruft damit wiederum die dritte Variante auf.

Aleksey Shipilëv hat auf seinem Blog die Performance der verschiedenen Varianten von Collection.toArray() verglichen und ist zu dem Ergebnis gekommen, dass die erste Variante, also die, die ein Object-Array zurückliefert, die schnellste ist. Von den Varianten, die ein Array des Ziel-Typs zurückliefern, sind die Varianten drei und vier am schnellsten. Dies ist kontraintuitiv, da dabei zwei Arrays erstellt werden (erst eines der Länge 0, danach eines der erforderlichen Länge). Warum die Übergabe eines Arrays der Länge 0 trotzdem schneller ist als die Übergabe eines Arrays der passenden Größe, kannst du in dem oben verlinkten Artikel nachlesen.

Die zweite Variante kann außerdem bei einer threadsicheren Collection Probleme bereiten: Ändert ein anderer Thread die Größe der Collection zwischen unserem Aufruf von size() und dem von toArray(), passt das übergebene Array nicht mehr. Ist die Collection gewachsen, legt toArray() ein neues Array an – unseres war umsonst erzeugt. Ist sie geschrumpft, ist das Array zu lang, und hinter dem letzten Element steht ein null.

Ich empfehle immer die vierte Variante, also die mit der Konstruktor-Referenz. Sie ist so schnell wie die dritte, kommt ohne das leere Array als Typvorlage aus und überlässt der Collection, wann und in welcher Größe sie das Array anlegt – die toArray()-Methode einer Collection-Implementierung kann also jederzeit optimiert werden, ohne dass wir in unserem Code etwas ändern müssen.

Set in Array konvertieren: Set.toArray()

Du kannst die oben gezeigten toArray()-Aufrufe unverändert verwenden, um auch ein Set in ein Array zu konvertieren:

Set<String> fruits = Set.of("honeydew", "dragonfruit", "boysenberry");
Object[] array1 = fruits.toArray();
String[] array2 = fruits.toArray(new String[fruits.size()]);
String[] array3 = fruits.toArray(new String[0]);
String[] array4 = fruits.toArray(String[]::new);

Wenn das Set eine definierte Iterations-Reihenfolge hat (wie z. B. ein TreeSet), dann garantieren die Set.toArray()-Methoden, dass die Elemente in Iterations-Reihenfolge in das Array kopiert werden.

Auch hier gilt meine Empfehlung, immer die vierte Variante einzusetzen.

Array aus einem Objekt-Stream erzeugen

Nicht nur Collections, sondern auch Streams haben toArray()-Methoden. Wir beginnen analog zu den Collections mit den generischen Objekt-Streams. Der folgende Code zeigt zwei Varianten, wie man einen String-Stream in ein Array umwandeln kann. Beachte, dass ein Stream nur einmal konsumiert, also auch nur einmal in ein Array umgewandelt werden darf – daher müssen wir für dieses Beispiel zwei Streams erzeugen:

Stream<String> stream1 = Stream.of("mango", "tomato", "coconut");
Object[] objects = stream1.toArray();

Stream<String> stream2 = Stream.of("cherry", "date", "raspberry");
String[] strings = stream2.toArray(String[]::new);

Hier gibt es nur zwei Varianten, nämlich die, die wir bei den Collections zuvor als Variante 1 und Variante 4 kennengelernt haben:

  • eine Variante ohne Typangabe, bei der nur ein Object-Array zurückgegeben werden kann,
  • und eine Variante mit einer Referenz auf den Konstruktor für den gewünschten Array-Typ.

Eine Variante, der ein Array des gewünschten Typs übergeben wird, existiert hier nicht. Dies deckt sich mit meiner Empfehlung, die Varianten 2 und 3 nicht für Collections zu verwenden. Warum gibt es diese Varianten dann bei Collections? Aus historischen Gründen: Als das Collections-Framework 1998 in Java 1.2 eingeführt wurde, gab es noch keine Methodenreferenzen, wie sie für die Übergabe des Konstruktors in Variante 4 benötigt werden.

Array aus einem primitiven Stream erzeugen

Im Gegensatz zu Collections gibt es bei Streams auch primitive Varianten, nämlich IntStream, LongStream und DoubleStream. Primitive Streams bieten nur eine einzige toArray()-Methode an. Da der Typ hier immer bekannt ist, ist eine Angabe des Typs nicht erforderlich.

Der folgende Code erstellt ein int-Array mit den Werten 1 bis 10, ein long-Array mit einer Zahlenfolge, die bei 1 beginnt und sich verdoppelt, solange der Wert unter 2.000 bleibt, und ein double-Array mit einer Zahlenfolge, die bei 1,0 beginnt und halbiert wird, bis insgesamt acht Elemente erstellt wurden:

int[] intArray = IntStream.rangeClosed(1, 10).toArray();
long[] longArray = LongStream.iterate(1, x -> x < 2000, x -> x * 2).toArray();
double[] doubleArray = DoubleStream.iterate(1.0, x -> x / 2.0).limit(8).toArray();

System.out.println("intArray = " + Arrays.toString(intArray));
System.out.println("longArray = " + Arrays.toString(longArray));
System.out.println("doubleArray = " + Arrays.toString(doubleArray));

Der Code gibt folgende Arrays aus:

intArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
longArray = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
doubleArray = [1.0, 0.5, 0.25, 0.125, 0.0625, 0.03125, 0.015625, 0.0078125]

2D-Arrays in Java deklarieren und initialisieren

Mehrdimensionale Arrays in Java sind nicht wirklich mehrdimensional, sondern Arrays von Arrays. Was das genau bedeutet und wie diese Arrays deklariert und initialisiert werden, zeige ich dir in den nächsten Abschnitten am Beispiel von zweidimensionalen Arrays.

2D-Array in Java deklarieren

Ein zweidimensionales Array deklarierst du wie folgt:

int[][] intMatrix;
String[][] stringMatrix;

Genau wie bei den eindimensionalen Arrays geben wir auch hier bei der Deklaration keine Größe an. Und auch bei mehrdimensionalen Arrays dürfen wir die Klammern im C-Stil nach dem Variablennamen schreiben:

int intMatrix[][];
String stringMatrix[][];

Wie auch bei den eindimensionalen Arrays präferieren die gängigen Java-Style-Guides die erste Variante.

2D-Array in Java initialisieren

Ein zweidimensionales Array kann direkt bei der Deklaration initialisiert werden – mit new gefolgt vom Typ und zwei Paaren aus eckigen Klammern:

int[][] intMatrix = new int[][]{{2, 3, 6}, {4, 5, 1}};

Wenn wir new verwenden, dürfen wir am Anfang auch var schreiben:

var intMatrix = new int[][]{{2, 3, 6}, {4, 5, 1}};

Oder wir lassen new mit der Typangabe weg – dann dürfen wir aber nicht var verwenden. Das ist die kürzeste Variante:

int[][] intMatrix = {{2, 3, 6}, {4, 5, 1}};

Natürlich können wir auch wieder Deklaration und Initialisierung auf zwei Zeilen aufteilen, müssen dann aber in beiden Zeilen den Typ explizit angeben:

int[][] intMatrix;
intMatrix = new int[][]{{2, 3, 6}, {4, 5, 1}};

Wir können auch ein leeres Array erzeugen (genauer gesagt, eines, das nur Nullen enthält) und dann die Felder in einem zweiten Schritt füllen:

int[][] intMatrix = new int[2][3];
intMatrix[0][0] = 2;
intMatrix[0][1] = 3;
intMatrix[0][2] = 6;
intMatrix[1][0] = 4;
intMatrix[1][1] = 5;
intMatrix[1][2] = 1;

Wichtig zu wissen ist, dass ein zweidimensionales Array in Java ein Array von Arrays ist. Die Beispiel-Arrays, die wir in diesem Abschnitt erzeugt haben, werden im Speicher wie folgt abgelegt:

Java-2D-Array – Darstellung im Speicher

Jede Zeile der Matrix ist ein separates Array. Du kannst auf diese Arrays auch zugreifen, sie z. B. wie folgt ausgeben:

int[] row0 = intMatrix[0];
int[] row1 = intMatrix[1];
System.out.println("row0 = " + Arrays.toString(row0));
System.out.println("row1 = " + Arrays.toString(row1));

Wir könnten das intMatrix-Array auch wie folgt erzeugen:

int[][] intMatrix = new int[2][3];
intMatrix[0] = new int[]{2, 3, 6};
intMatrix[1] = new int[]{4, 5, 1};

Die Unter-Arrays intMatrix[0] und intMatrix[1] werden dabei in der ersten Zeile initial jeweils auf {0, 0, 0} gesetzt und dann in der zweiten und dritten Zeile durch neue Arrays überschrieben.

Wir können die Größenangabe für die zweite Dimension in der ersten Zeile auch weglassen:

int[][] intMatrix = new int[2][]; // ⟵ without second dimension length
intMatrix[0] = new int[]{2, 3, 6};
intMatrix[1] = new int[]{4, 5, 1};

In diesem Fall sind intMatrix[0] und intMatrix[1] initial jeweils null.

Es ist übrigens nicht vorgeschrieben, dass alle Unter-Arrays gleich lang sein müssen. Auch folgendes ist erlaubt:

int[][] intMatrix = new int[2][];
intMatrix[0] = new int[]{2, 3, 6};
intMatrix[1] = new int[]{4, 5, 1, 9, 7};

Und auch das dürften wir schreiben:

int[][] intMatrix = {{2, 3, 6}, {4, 5, 1, 9, 7}};

Die in den letzten zwei Beispielen erzeugten 2D-Arrays können wir uns grafisch wie folgt vorstellen:

Java-2D-Array mit unterschiedlich langen Zeilen – Darstellung im Speicher

Die in den vorherigen Abschnitten behandelten Methoden Arrays.fill(), Arrays.setAll(), clone(), System.arraycopy(), Arrays.copyOf() und Arrays.copyOfRange() lassen sich auf beiden Ebenen solch eines verschachtelten Arrays anwenden.

Der folgende Code z. B. erzeugt eine Matrix mit den Produkten des kleinen Einmaleins:

int[][] products = new int[11][11];
for (int i = 0; i < 11; i++) {
  int finalI = i; // ⟵ we need an effectively final variable for the lambda
  Arrays.setAll(products[i], j -> finalI * j);
}

Der folgende Code setzt alle Zeilen einer zweidimensionalen Matrix auf ein Array mit den Werten eins bis vier:

int[][] matrix = new int[3][];
Arrays.fill(matrix, new int[]{1, 2, 3, 4});

Beachte allerdings, dass wir dieses innere Array nur einmal erzeugt haben und dass alle Zeilen auf dasselbe innere Array verweisen:

Java-2D-Array mit geteiltem inneren Array

Wenn du den folgenden Code ausführst, wirst du sehen, dass die vermeintliche Änderung eines einzigen Feldes der Matrix eine ganze Spalte verändert hat:

matrix[1][1] = 99;
System.out.println("matrix = " + Arrays.deepToString(matrix));

Um für jede Zeile ein separates Array zu erzeugen, kannst du Arrays.setAll() verwenden, da hier das im zweiten Parameter übergebene Lambda für jede Zeile aufgerufen wird:

Arrays.setAll(matrix, ignored -> new int[]{1, 2, 3, 4});

Es ist gut, diese Besonderheiten von mehrdimensionalen Arrays in Java zu kennen.

Fazit

In diesem Artikel hast du verschiedene Methoden kennengelernt, um in Java Arrays zu erzeugen – von der Initialisierung mit statischen Werten oder Default-Werten über das Befüllen eines Arrays mit Arrays.fill() oder Arrays.setAll() und das Kopieren von Arrays mit clone(), System.arraycopy() und Arrays.copyOf() bis hin zur Umwandlung aus bestehenden Datenstrukturen wie Listen, Sets und Streams.

Du kennst nun außerdem die Besonderheiten mehrdimensionaler Arrays in Java und weißt, worauf du bei deren Verwendung achten musst.

Wenn dir dieser Artikel gefallen hat, freue ich mich über eine Bewertung auf meinem ProvenExpert-Profil.

👉 Bewertung abgeben

Lust auf noch mehr Wissen?

In meinem Blog findest du viele Artikel zu Java, Softwarearchitektur und Performance von grundlegenden Konzepten bis hin zu fortgeschrittenen Patterns.

Wenn du tiefer einsteigen willst, schau dir meine Trainings an: praxisnah, verständlich und direkt auf euren Projektalltag übertragbar. Statt Theorie vermittle ich Prinzipien, die euch helfen, Code langfristig besser, wartbarer und performanter zu schreiben.

Zu den Java-Schulungen

Werde ein:e bessere:r Java-Entwickler:in

Mit meinem kostenlosen Newsletter bleibst du vorn. Modernes Java: neue Versionen & Features, Performance und JVM-Insights – 1x im Monat.

Suche