michael.eichberg@dhbw-mannheim.de, Raum 149B
1.0
Eindimensionale Felder sind Datentypen, die es ermöglichen eine Liste mit einer fixen Anzahl von Werten gleichen Datentyps zu verwalten
Die Tage der verschiedenen Monate können als ein Feld mit der Größe 12 abgelegt werden
Monat (Index): |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Tage: |
31 |
29 |
31 |
30 |
31 |
30 |
31 |
31 |
30 |
31 |
30 |
31 |
Variablen mit einem Feld-Datentyp werden durch den Datentyp der einzelnen Elemente gefolgt von eckigen Klammern deklariert.
<Typ>[] <Bezeichner> oder <Typ> <Bezeichner>[]
Deklaration eines Feldes
int[] daysPerMonth;
Alternativ möglich, aber unüblich geworden:
int daysPerMonth[];
Initialisierung eines leeren Arrays:
daysPerMonth = new int[12];
// daysPerMonth ==> int[12] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
<Bezeichner> = new <Typ>[<Größe>]
Initialisierung eines Arrays mit konkreten Werten:
daysPerMonth =
new int[]{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
bzw. ohne Verwendung von new
:
int [] daysPerMonth =
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
// ⚠️ Diese Art der Initialisierung eines Arrays direkt über
// "= {...}" kann nur bei der Deklaration erfolgen.
<Bezeichner> = {<Ausdruck> (, <Ausdruck>)* }
Nach der Initialisierung lässt sich die Größe eines Feldes nicht mehr ändern.
Die Länge eines Arrays kann mittels length
abgefragt werden:
int numberOfMonths = daysPerMonth.length;
// numberOfMonths ==> 12
Wird ein Feld nur deklariert und nicht initialisiert, dann hat die Variable den speziellen Wert null
.
Auf einzelne Elemente eines Feldes kann mittels eines Indexes und dem Feldzugriff-Operator []
lesend oder schreibend zugegriffen werden, z.B. mit a[1]
.
Wertzuweisung eines Feldelementes: Verwendung des Feldzugriffoperators auf der linken Seite einer Zuweisung, z.B. a[1] = 1
;
Auslesen eines Feldelementes: jegliche andere Verwendung des Feldzugriffoperators.
Verwendung eines ungültigen Indexes führt zu einer Ausnahme/einem Laufzeitfehler (ArrayIndexOutOfBoundsException
).
daysPerMonth[13]
==> Exception java.lang.ArrayIndexOutOfBoundsException:
Index 13 out of bounds for length 12
Beispiel: Lesender Zugriff auf ein Element eines Feldes
int daysInFebruary = daysPerMonth[1]; // Index "1" => 2. Element
// daysInFebruary ==> 29
<Bezeichner>[<Index>]
Beispiel: Schreibende und lesende Zugriffe
int daysPerMonth[] = new int[12]; // Deklaration
daysPerMonth[0] = 31;
daysPerMonth[1] = 29;
//…
daysPerMonth[10] = 30;
daysPerMonth[11] = 31;
System.out.println("daysPerMonth[1] = " + daysPerMonth[1]);
Häufig greift man auf Arrays mittels einer Schleife zu:
for (int i = 0; i < daysPerMonth.length; i++) {
println("daysPerMonth[" + i + "] = " + daysPerMonth[i]);
}
Bzw. mit einer for-each
-Schleife, wenn der Index nicht benötigt wird:
for (int days : daysPerMonth) {
println("days = " + days);
}
Wochentagsberechnung mit Feld
Nehmen Sie Ihr Programm zur Berechnung des Wochentags und ersetzen Sie die Logik zur Bestimmung des Namens eines Wochentags durch ein Feld mit den Namen der Wochentage:
String[] dayInWeekName = ...
Eine Variable mit einem Feld-Datentyp speichert eine (virtuelle) Speicheradresse zu den Feld-Inhalten (Werten).
int[] a = {1, 2, 3};
int[] b = a; // b referenziert das gleiche Feld wie a;
// ist "nur" eine Kopie des Zeigers auf das Feld.
b[0] = 4;
println(a[0]);
// ==> 4
Dies ist insbesondere in älteren Programmiersprachen (z. B. C) ein häufiger Fehler, der zu Speicherlecks führt. Dies hat dazu geführt, dass das Weisse Hause die Empfehlung ausgesprochen hat, solche alten Sprachen nicht mehr zu verwenden. In Java und vielen anderen modernen Programmiersprachen ist dies nicht möglich.
int[] a = { 1, 2, 3, 4, 5, 6, 7 };
int[] b = a;
final
Der final
-Modifizierer verhindert nur, dass die Referenz auf ein Feld geändert werden kann.
Der Inhalt des Feldes kann jedoch geändert werden.
D. h. der Nutzen von final
ist im Zusammenhang mit Referenzdatentypen im Allgemeinen begrenzt.
1void main() {
2final int[] a = {1, 2, 3};
3println(a[0] = -1);
4println(Arrays.toString(a));
5// a = new int[]{}; // IllegalAccess.java:
6// error: cannot assign a value to final variable a
7}
Der Vergleich zweier Feldvariablen mit dem ==
bzw. !=
Operator vergleicht nicht den Inhalt der Felder, sondern die virtuelle Speicheradresse (ähnlich bei Strings).
Der Vergleich der Inhalte muss über den Vergleich der einzelnen Feldelemente erfolgen bzw. über Hilfsmethoden wie z.B. java.utils.Arrays.equals(...)
.
int[] a = {1, 2, 3};
int[] b = {1, 2, 3};
int[] c = a;
println(a == b); // ==> false
println(a == c); // ==> true
println(Arrays.equals(a, b)); // ==> true
Konzeptionell führt Arrays.equals(...) eine Schleife über die Elemente der beiden Arrays aus und vergleicht die Werte der Elemente. Der Vergleich der Referenzen erfolgt über den Operator ==
.
Eine Kopie der Inhalte muss über das Erzeugen eines neuen Feldes und Kopie der einzelnen Feldelemente erfolgen bzw. über Hilfsmethoden wie z. B. System.arraycopy(...)
oder java.utils.Arrays.copyOf(...)
oder <Array>.clone()
.
Beispiel mit <Array>.clone()
:
jshell> final var clone = daysPerMonth.clone();
// clone ==> int[12] { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
jshell> clone[0] = 35;
jshell> daysPerMonth[0]
// ==> 31
Dokumentation: java.util.Arrays
Die Parameter und der Rückgabewert einer Methode können vom Typ eines Feldes sein.
Bei der Übergabe eines Feldes an eine Methode bzw. der Rückgabe eines Feldes wird eine Kopie der Referenz auf das Feld erzeugt. Es wird keine Kopie der Arrays als solches erzeugt.
Änderungen an den Feldelementen innerhalb der Methode wirken sich auf das ursprüngliche Feld aus.
Der Rückgabewert kann direkt zur Initialisierung eines Feldes verwendet werden.
void incrementAll(int[] a) {
for (int i = 0; i < a.length; i++) { a[i]++; }
}
int[] getLengths(String[] strings) {
int[] lengths = new int[strings.length];
for (int i = 0; i < strings.length; i++) {
lengths[i] = strings[i].length();
}
return lengths;
}
getLengths(new String[]{"a","ab","abc"})
// ==> int[3] { 1, 2, 3 }
Arrays vergleichen
Schreiben Sie eine Methode, die prüft ob eine Array zum Speichern von int
Werten, mit dem Beginn eines anderen Arrays von int
-Werten übereinstimmt. Vergleichen Sie die Elemente der beiden Arrays mit Hilfe des ==
bzw. !=
Operators.
D. h. die Methode soll true
zurückgeben, wenn alle Elemente des ersten Arrays (a) mit den ersten Elementen des zweiten Arrays b übereinstimmen.
Die Methode soll die folgende Signatur haben und auch alle Sonderfälle abdecken!
boolean startsWith(int[] a, int[] b);
Skalarprodukt
Schreiben Sie eine Methode, die zwei gleich lange Arrays von int
Werten entgegennimmt und das Skalarprodukt der beiden Arrays berechnet.
Zur Erinnerung: Das Skalarprodukt ist die Summe der Produkte der Elemente an der gleichen Position in den beiden Arrays (a[0] * b[0] + a[1] * b[1] + ...
).
Kommandozeilenparameter
Die main
Methode eines Java Programms bekommt als Parameter ein Feld von String
s übergeben. Dieser Parameter wird args
genannt (void main(String[] args)
).
Nehmen Sie Ihr Programm zur Berechnung des BMIs und verwenden Sie Kommandozeilenargumente als Parameter für Ihre bmi
Funktion.
Prüfen Sie ob die Anzahl der Parameter korrekt ist und geben Sie eine Fehlermeldung aus, wenn dies nicht der Fall ist.
Faktorisieren Sie (ggf.) die Funktionalität zur Berechnung des BMI in zwei Methoden:
Eine Methode, die Strings entgegennimmt und eine die double
Werte entgegennimmt.
Beispielinteraktion:
$ java --enable-preview BMIBerechnen.java
Bitte geben Sie Ihr Gewicht in Kilogramm und Ihre Größe in Mete an.
bzw.
$ java --enable-preview BMI.java 83.1 1.89
Ihr BMI beträgt: 23.26362643822961 - Normalgewicht
D. h. der Nutzer übergibt direkt die Werte für das Gewicht und die Größe und wird nicht aufgefordert diese Werte einzugeben.
TODO