In Java gibt es zwei Arten der Referenzdatentypen. Es gibt Felder und Klassen. Die Referenzdatentypen werden etwas anders behandelt als die einfachen Datentypen. Die Variable eines einfachen Datentypen enthält die Speicheradresse in der der Wert (Inhalt) steht. Bei den Referenzdatentypen zeigt die Variable auf eine Speicheradresse in der eine Referenz steht diese enthält eine weitere Speicheradresse in der erst jetzt der Wert (Inhalt) steht. Damit ist es bei den Referenzdatentypen möglich, dass zwei Referenzdatentypen die selbe Referenz besitzen, damit verändert sich der Wert beider Referenzdatentypen wenn er bei einer davon geändert wird.
Felder
Wir wollen uns ein Programm schreiben dass Vornamen, Nachnamen und das Geburtsdatum von Freunden in eine Variable speichert und nach Wunsch auch wieder ausgegeben werden kann. Wie schreibt man jetzt so ein Programm? Mit einfachen Datentypen müssten wir für jeden Vornamen, Nachnamen und Geburtsdatum eine eigene Variable deklarieren. Dies wären bei 10 Namen schon 30 Variablen. Es wäre sehr umständlich und wir könnten damit auch nur die Daten von 10 Personen speichern. Dafür haben wir die Felder damit erleichtern wir uns die Schreibarbeit erheblich. Durch Felder kann man mehrere Variablen durch einen gemeinsamen Namen ansprechen und das lediglich durch den Index (ganzzahliger nicht negativen Wert) des Feldes.
Eine Referenzvariable von Feldern werden ähnlich deklariert wie die Variable von einfachen Datentypen.
Hier das Beispiel "Namensliste" das wir noch erweitern werden:
- public class Namensliste {
- public static void main(String[] args) {
- // Deklaration von Referenzen
- String[] vorname;
- String[] nachname;
- String[] geburtsdatum;
- }
- }
String ist der Komponentyp des Feldes. Mit der eckigen Klammer nach dem Komponentyp String teilen wir den Compiler mit, dass der Bezeichner von String eine Referenzvariable ist.
Jetzt legen wir die Größe der Felder mit Hilfe des new-Operators fest:
- ...
- String [] geburtsdatum
- // Erzeugen der Felder
- vorname = new String[3];
- nachname = new String[3];
- geburtsdatum = new String[3];
- ...
Unsere Felder haben jeweils die Feldlänge von 3 und es werden die Referenzen dazu gesetzt. Die Feldgröße muss mit einen int-Wert angegeben sein. Der Wert braucht jedoch nicht notwendigerweise eine konstanter Wert sein, er kann auch als Ausdruck vom Typ byte, short, oder char sein. Der Wert wird implizit nach int umgewandelt.
Diese Anweisungen wären auch möglich:
- byte b = 5;
- double[] feld;
- feld = new double[23 * b];
und
- double[] feld;
- feld = new double['e'];
Da unsere Felder alle die selbe Länge in unserem Programm haben, können wir es auch so schreiben:
- ...
- public static void main(String[] args) {
// Deklaration und initialisieren einer
- // einfachen konstanten Variable
- int index = 3;
- // Deklaration von Referenzen
- String[] vorname;
- String[] nachname;
- String[] geburtsdatum;
- // Erzeugen der Felder
- vorname = new String[index];
- nachname = new String[index];
- geburtsdatum = new String[index];
- }
- ...
Dadurch ist es uns möglich mit nur einer Änderung die gewünschte Feldlänge der drei Felder anzupassen.
Jetzt initialisieren wir im Beispiel "Namensliste" einen Standartwert mit der for-Anweisung und geben die Liste auf der Konsole aus.
- ...
- public static void main(String[] args) {
- // Deklaration und initialisieren einer
- // einfachen konstanten Variable
- int index = 3;
- // Deklaration von Referenzen
- String[] vorname;
- String[] nachname;
- String[] geburtsdatum;
- // Erzeugen der Felder
- vorname = new String[index];
- nachname = new String[index];
- geburtsdatum = new String[index];
- // Initalisierung der Felder
- for(int i = 0; i < index; i++) {
- vorname[i] = "leer";
- nachname[i] = "leer";
- geburtsdatum[i] = "leer";
- }
- // Ausgabe auf der Konsole
- for(int i = 0; i < index; i++) {
- System.out.println("Vorname : " + vorname[i]);
- System.out.println("Nachname : " + nachname[i]);
- System.out.println("Geburtsdatum : " + geburtsdatum[i]);
- System.out.println();
- }
- }
- ...
Die for-Anweisung in Zeile 19 übergibt an jedes Feldelement den String "leer", indem es jedes Feldelement durch das hochzählen des Index alle Feldelemente nacheinander anspricht. Die Feldlänge beginnen immer mit 0 damit ist die Länge um 1 vermindert. Das heißt, wenn 3 Feldelemente erzeugt werden, beginnt der Index mit 0 und geht bis 2, da Index 3 eigentlich schon das vierte Feldelement wäre.
Es ist natürlich auch möglich, Felder bei der Deklaration, gleich Werte zu initialisieren. Dadurch wird der Compiler den new-Operator automatisch ausführen und dadurch auch die entsprechende Feldlänge erzeugen.
Hier ein paar Beispiele:
- int[] feld1 = {5, 6, 9, 7};
- double[] feld2 = {12.345, 12.43, -12.34455};
- String[] feld3 = {"Dies", "ist", "ein", "String"};
Den Ausdruck in den { und } bezeichnet man als Feld-Initialisierer, ist das Feld sehr groß und regelmäßig aufgebaut, wird man diese Schreibweise nicht anwenden.
Die Größe eines Feldes kann aber nicht immer genau bei der Programmierung festgelegt werden, da es oft unvorhersehbar ist wie groß das Feld im Programmablauf dann wirklich ist. Bei dem erstellen eines Feldes, wird seine Feldlänge in einem zusätzlichen Element abgespeichert, der vom Datentyp int ist. Durch dieses Element können wir mit dem Variablennamen und gefolgt von .length, die Länge des Feldes erhalten.
Wir ändern unser Programm etwas ab:
- ...
- // Wenn die Felder nicht gleich groß sind
- // wird eine Fehlermeldung ausgegeben.
- if (vorname.length != nachname.length ||
- vorname.length != geburtsdatum.length) {
- System.out.println("Achtung! Die Felder besitzen
nicht die gleiche länge.");
- }
- else {
- // Initalisierung der Felder
- for(int i = 0; i < vorname.length &&
- i < nachname.length &&
- i < geburtsdatum.length; i++) {
- vorname[i] = "leer";
- nachname[i] = "leer";
- geburtsdatum[i] = "leer";
- }
- // Ausgabe auf der Konsole
- for(int i = 0; i < vorname.length &&
- i < nachname.length &&
- i < geburtsdatum.length; i++) {
- System.out.println("Vorname : " + vorname[i]);
- System.out.println("Nachname : " + nachname[i]);
- System.out.println("Geburtsdatum : " + geburtsdatum[i]);
- System.out.println();
- }
- }
- ...
Damit kein Fehler vorkommt, da alle drei Felder die gleiche Feldlänge im Beispiel haben sollten werden sie in einer if-Anweisung in Zeile 5 und 6 auf unterschiedliche Längen überprüft, wenn sie nicht gleich lang sind wird eine Fehlermeldung auf der Konsole ausgegeben. Wenn die Felder die selbe länge haben, wird der Anweisungsblock der else-Anweisung in Zeile 9 bis 28 ausgeführt.
In den beiden for-Anweisungen in Zeile 11 und 20, werden alle drei Felder überprüft. Damit der Index die Feldlänge nicht überschreitet, wenn doch, wird die for-Anweisung beendet.
Wer die Werte eines Feldes, in ein anderes Feld kopieren möchte, sollte etwas beachten. Hier ein Beispiel:
- feld2 = feld1;
Hier wird nur die Referenz von feld1 dem feld2 zugewiesen, also nur die Adresse und keine Werte.
Damit zeigen beide Felder auf die gleiche Speicheradresse. Wenn wir jetzt einen Wert in feld1 verändern wird dieser auch in feld2 verändert. Wenn wir eine richtige Kopie erstellen wollen, dann mit einer for-Anweisung:
- for(int i = 0; i < feld1.length; i++) {
- feld2[i] = feld1[i];
- }
Damit werden die Werte von jedem Element übergeben und beide Felder haben dennoch verschiedene Speicheradressen.
Es gibt noch eine Möglichkeit um den Inhalt eines Feldes zu kopieren. Hier ein Beispiel:
- System.arraycopy(feld1, 0, feld2, 0, feld1.length);
Die Methode arraycopy kopiert ganze Inhalte von Feldern oder Teile eines Feldes in ein anderes Feld. Die Methode verlangt fünf Werte. Der erste Wert ist das Feld deren Inhalt kopiert werden soll. Der zweite Wert ist der Startindex des Feldes deren Inhalt kopiert werden soll. Der nächste Wert, ist das Feld in das kopiert werden soll. Dann kommt der Startindex ab wann in das Feld kopiert werden soll. Als letztes kommt die Anzahl der Feldelemente die kopiert werden sollen, im Beispiel ist es das ganze feld1, deshalb feld1.lenght.
Einige werden sich schon gedacht haben, dass es etwas unpraktisch ist drei Felder zu verwalten, wenn sie eigentlich zusammen gehören und auch noch die gleiche Feldlänge haben sollen. Dafür gibt es die mehrdimensionale Felder
Mehrdimensionale Felder
Hier ist unser Programm mit einem mehrdimensionalen Feld:
- public class Namensliste {
- public static void main(String[] args) {
- // Deklaration eiens mehrdimensionalen Feldes
- String[][] liste;
- // Erzeugen des mehrdimensionalen Feldes
- liste = new String[10][3];
- for(int i = 0; i < liste.length; i++) {
- for(int t = 0; t < liste[i].length; t++) {
- // Initialisiere das // mehrdimensionale Feld
- liste[i][t] = "leer";
- }
- }
- // Ausgabe auf der Konsole
- for(int i = 0; i < liste.length; i++) {
- for(int t = 0; t < liste[i].length; t++) {
- System.out.println("Vorname : " + liste[i][t]);
- System.out.println("Nachname : " + liste[i][t]);
- System.out.println("Geburtsdatum : " + liste[i][t]);
- System.out.println();
- }
- }
- }
- }
Es hat sich einiges geändert und das Programm ist dabei sogar kleiner geworden.
Wir deklarieren unser mehrdimensionales Feld:
- String[][] liste;
Es ist zweidimensional und deshalb müssen wir nach dem Komponententyp zwei eckige Klammern auf und zu schreiben. Danach folgt die Referenzvariable. Natürlich ist es auch möglich ein dreidimensionales Feld und noch größere Felder zu deklarieren, wir müssen nur noch mehr eckige Klammern ergänzen.
Jetzt legen wir die Feldlänge mit dem new-Operator:
- liste = new String[10][3];
Wie wir sehen erzeugen wir ein Feld mit 10 Elementen und jedes Element enthält nochmals 3 Elemente. Wir können auch erst die ersten 10 Elemente erzeugen und die anderen Elemente erst später erzeugen. Hier ein Beispiel:
- ...
- liste = new String[10][];
- for (int i = 0; i < liste.length; i++) {
- liste[i] = new String[3];
- }
- ...
Wir können jetzt natürlich nicht mehr "liste = new String[10][3];" schreiben da die ersten 10 Felder schon erzeugt wurden. Jetzt müssen wir jedes Feldelement einzeln aufrufen, um die 3 Felder für jedes Element erzeugen zu können. Um es uns einfacher zu machen, erzeugen wir die Felder in einer for-Anweisung. Mit .length ermitteln wir die Länge der Elemente in den ersten eckigen Klammen. In Zeile 6 rufen wir nacheinender die Elemente mit dem Index ab und erzeugen mit dem new-Operator die 3 Elemente.
Hier übergeben wir an jedes Feldelement den String "leer":
- liste[i][t] = "leer";
In der letzten for-Anweisung geben wir die Felder auf der Konsole aus.
Mehrdimensionale Felder brauchen nicht immer gleich lang sein, hier ein Beispiel:
- int[][] feld = new int[3][];
- feld[0] = new int[6];
- feld[1] = new int[2];
- feld[2] = new int[9];
Hier werden 3 Felder erzeugt und jedes Feld wird mit einer andere Länge erzeugt.
Keine Kommentare:
Kommentar veröffentlichen