1. Felder und Strings Eigenschaften von Referenzdatentypen 1. Referenzdatentypen: Felder und Strings • Referenzdatentypen sind Konstrukte, mit deren Hilfe wir aus einfachen Datentypen neue “eigene” Typen erzeugen können. • In Java gibt es prinzipiell zwei Arten von Referenzdatentypen: Felder und Klassen. • In diesem Kapitel lernen wir den Umgang mit Feldern und die Benutzung der Klassen String und StringBuffer. • Die Nutzung von Klassen ist Thema des nächsten Kapitels. • Die Definition eigener Klassen ist Thema des übernächsten Kapitels. 1. Felder und Strings Eigenschaften von Referenzdatentypen • Im Unterschied zum einfachen Datentyp wird der Wert 124 der Variablen r nicht als numerischer Wert interpretiert, sondern als Adresse für eine andere Speicherzelle. Dort findet sich der “eigentliche” Wert bzw. unser “eigentliches” Objekt. • Mit der Literalkonstanten null repräsentieren wir eine Referenz, die auf nichts (in das Nirgendwo) verweist. Wenn die Variable r von einem Referenztyp ist, dann sind r = null; ... if ( r == null ) ... gültige Anweisungen. • Grafische Notation für Variablen: b Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 10 1. Felder und Strings Eigenschaften von Referenzdatentypen Referenz- vs. einfache Datentypen b Adresse im Speicher ... Inhalt ... Typ 96 4711 int r ... 104 ... 124 ... ... r Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 1. Felder und Strings 12 Einfache Datentypen Rückblick: Einfache Datentypen (1) • einfacher Datentyp: Eine Speicherzelle, die mit einer Variablen assoziiert ist, enthält den Wert der Variablen (direkter Zugriff). • Referenztyp: Eine Speicherzelle, die mit einer Variablen assoziiert ist, enthält eine Referenz (Verweis, Zeiger) auf eine andere Speicherzelle, die den Wert enthält (indirekter Zugriff). symbolische Adresse 4711 124 ... ... • Ganzzahlige Datentypen long int short byte Repräsentation: Zweierkomplement • Gleitkommatypen double float Repräsentation: 32 bzw. 64 Bit im IEEE 754 Standard • char Repräsentation: als vorzeichenloser 16-Bit Integerwert • boolean Referenz Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 11 Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 13 1. Felder und Strings Einfache Datentypen Rückblick: Einfache Datentypen (2) 1. Felder und Strings Einfache Datentypen • Die folgende Anweisung dagegen liefert einen Fehler beim Compilieren: int i = 3.0; Grund: 3.0 ist eine double-Zahl. Bei einer Umwandlung nach int geht eventuell Information verloren. Zu einem einfachen Datentyp gehört • Stattdessen könnten wir eine explizite Typkonvertierung (explicite Typecast) durchführen. Hierzu schreibt man den Zieldatentyp in Klammern vor die entsprechende Zahl oder Ausdruck. • sein Wertebereich, • sein lexikalischer Bereich (Literale) und • die zur Verfügung stehenden Operationen. (int) 3.14 Hier würde der Compiler die Nachkommastellen abschneiden. • Eine Umwandlung von boolean in einen anderen Datentyp ist nicht möglich. Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 1. Felder und Strings 14 Einfache Datentypen Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 1. Felder und Strings 16 Eindimensionale Felder Felder Einfache Datentypen: Implizite und explizite Typumwandlung • Wir wollen die Addition 92233720366854775000L + 807 durchführen. Der Plus-Operator ist aber nur für Werte des gleichen Typs definiert. Was tun? • Der Java-Compiler erkennt, daß der Datentyp zur linken Zahl einen Wertebereich hat, der den der rechten Zahl umfasst. So wird die 807 vom Compiler in eine automatisch long-Zahl umgewandelt. ☞ implizite Typkonvertierung (implicite typecast) • Implizite Typkonvertierungen treten immer dann auf, wenn ein kleinerer Zahlenbereich in einen größeren Zahlenbereich abgebildet wird. byte → short → int → long char → int float → double • Ganzzahlige Datentypen können auch implizit in Gleitkommatypen umgewandelt werden, obwohl dabei Rundungsfehler auftreten können. Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 15 • Felder (Arrays) gestatten es, mehrere Variablen durch einen gemeinsamen Namen anzusprechen und lediglich durch einen Index zu unterscheiden. • Alle diese indizierten Variablen haben dabei den gleichen Typ (Komponententyp, Basistyp). • Die Variablen selbst werden als Komponenten des Feldes bezeichnet. • Der Index zum Ansprechen der Komponenten ist vom Typ int. Hierbei sind nur nichtnegative Werte erlaubt. • Wir können uns vorstellen, daß die Komponenten eines Feldes aufeinanderfolgend im Speicher des Rechners abgelegt sind. • Der Index für eine Komponente ergibt sich dabei aus der Position innerhalb des Feldes, von Null aufwärts gezählt. • Beispiel: – Repräsentation eines Vektors des IRn: Feld mit double als Komponententyp Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 17 1. Felder und Strings Eindimensionale Felder Deklaration von Feldern 1. Felder und Strings Eindimensionale Felder Deklaration und Erzeugung können auch zusammen erfolgen. Beispiele: int[] zahlenfolge = new int[20]; double[] vektor = new double[3]; Syntax: Komponententyp[] Variablenname; Bitte beachten Sie: Beispiele: int[] zahlenfolge; double[] vektor; • Die eckigen Klammern machen deutlich, daß die Variable ein Feld referenziert, mit dem Typ links von [] als Komponententyp. • Als Komponententyp sind nicht nur einfache Datentypen, sondern auch Referenztypen erlaubt. ☞ Die Größe eines Feldes ist nicht Bestandteil des Typs. Sie wird erst bei der Erzeugung des Feldes festgelegt. ☞ Die Feldlänge kann durch einen Ausdruck angegeben werden. ☞ Einer Feld-Variable können jederzeit andere Felder gleichen Typs zugewiesen werden. double[] vektor = new double[3]; double[] vektor2 = new double[7]; String[] wortliste; vektor = new double[3]; vektor = new double[5]; vektor = vektor2; • Insbesondere sind auch Feldtypen als Komponententyp erlaubt (hierzu später mehr). Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 1. Felder und Strings 18 Eindimensionale Felder Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 1. Felder und Strings Erzeugung von Feldern 20 Eindimensionale Felder Komponentenzugriff und -initialisierung double[] vektor = new double[3]; ☞ Die Deklaration einer Feld-Variablen erzeugt kein Feld! • Nach der Deklaration existiert eine Variable, die eine Referenz auf ein Feld als Wert aufnehmen, kann. • Das eigentliche Feld existiert aber noch nicht. Welchen Wert haben die Feldkomponenten nach der Erzeugung? Syntax zur Erzeugung von Feldern: • • • • • Variablenname = new Komponententyp [ Feldlänge ]; Beispiele: Dies ist für jeden möglichen Komponententyp festgelegt: ganzzahlige Typen: 0 char: ’\0’ double bzw. float: 0.0 bzw. 0.0f boolean: false Referenztyp: null zahlenfolge = new int[20]; vektor = new double[3]; Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 19 Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 21 1. Felder und Strings Eindimensionale Felder Syntax für die Wertzuweisung an eine Komponente: 1. Felder und Strings Eindimensionale Felder • Statt Erzeugung mit new und anschließender Initialisierung durch Wertzuweisungen ist auch eine verkürzte Schreibweise möglich. • Beispiele: Variablenname[Index] = Wert; int[] lottozahlen = { 6, 11, 19, 21, 30, 40 }; double[] vektor = { 1.0, 2.0, -1.0 }; String[] wortliste = { "ganz", "viele", "Wörter" }; Beispiel: vektor[0] = 1.0; vektor[1] = 2.0; vektor[2] = -1.0; • Index muß ein Ausdruck sein, der einen int-Wert liefert. • Der Wert für Index muß zwischen 0 und Feldlänge-1 liegen. • Wert kann natürlich ein beliebiger Ausdruck passend zum Komponententyp sein. int[] quadratFolge = new int[100]; • Die geklammerten Ausdrücke heißen Feld-Initialisierer (array initializer). • Nur Literale oder Konstanten dürfen als Wert in einem Feld-Initialisierer auftreten. • Diese Schreibweise ist nur in Verbindung mit einer Deklaration erlaubt, nicht für eine gewöhnliche Zuweisung. for (int i=0 ; i<100 ; i++ ) quadratFolge[i] = i*i; Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 1. Felder und Strings 22 Eindimensionale Felder Syntax für den Zugriff auf den Wert einer Komponente (als Ausdruck): Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 1. Felder und Strings 24 Eindimensionale Felder Ermittlung der Länge von Feldern Variablenname[Index] Beispiel: • Bei der Erstellung eines Feldes wird dessen Länge in einem zusätzlichem Element vom Typ int abgespeichert. • Auf dieses Element kann mit double summe = 0.0; for (int i=0 ; i<3 ; i++ ) { System.out.println( "vektor[" + i + "] = " + vektor[i] ); summe = summe + vektor[i] * vektor[i]; } System.out.println("Laenge des Vektors: " + Math.sqrt( summe )); Variablenname.length zugegriffen werden. • Beispiel: double[] vektor = { 1.0, 2.0, -1.0 }; for (int i=0 ; i<vektor.length ; i++ ) System.out.println( "vektor[" + i + "] = " + vektor[i] ); Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 23 Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 25 1. Felder und Strings Eindimensionale Felder 1. Felder und Strings Eindimensionale Felder 2. Nutzung der Methode System.arraycopy: Kopieren und Vergleichen von Referenzen System.arraycopy( Quelle, QuelleStartIndex, Ziel, ZielStartIndex, Anzahl ); double[] v = { 1.0, 3.0, 5.0, 10.0 }; double[] q = v; for ( int i=0 ; i<q.length ; i++ ) q[i] = q[i]*q[i]; for ( int i=0 ; i<q.length ; i++ ) System.out.println( "Das Quadrat von " + v[i] + " ist " + q[i] ); Was wird ausgegeben und warum? Hierbei ist: • Quelle: Feld, von dem kopiert werden soll • QuelleStartIndex: Index, ab der Quelle übertragen werden soll • Ziel: Feld, in das kopiert werden soll • ZielStartIndex: Index, ab dem die Eintragungen erfolgen sollen • Anzahl: Anzahl der zu kopierenden Komponenten 3. Nutzung der vordefinierten Methode clone. Hierzu später mehr. ☞ Alle diese Möglichkeiten legen eine sogenannte flache Kopie an. ☞ D.h. für die Komponenten selbst wird die übliche Zuweisung durchgeführt. ☞ Dies kann problematisch sein, wenn der Komponententyp selbst eine Referenzdatentyp ist (Referenzkopie). Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 26 1. Felder und Strings Eindimensionale Felder • Die Zuweisung q = v; führt zu einer sogenannten Referenzkopie. • Es wird keine Kopie des Feldes angelegt, sondern q erhält die Referenz, die in v hinterlegt ist. • Wirkung: q und v verweisen auf das gleiche Feld. v 1.0 3.0 5.0 10.0 Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 28 1. Felder und Strings Eindimensionale Felder • int[] feld1 = { 1, 2, 3 }; int[] feld2 = { 1, 2, 3 }; • Der Ausdruck feld1 == feld2 liefert false! • Begründung: Bei Referenzdatentypen bedeutet == nicht, daß die Inhalte der referenzierten Felder (oder Objekte) verglichen werden. • Stattdessen wird geprüft, ob die Referenzen die gleiche Speicherstelle adressieren. feld1 1 2 3 feld2 1 2 3 q Für die Herstellung einer “echten Kopie” haben wir die folgenden Möglichkeiten: • Wie vergleicht man dann die Inhalte von Feldern? ☞ Ausprogrammieren • Achtung: Der Komponententyp kann wieder ein Referenztyp sein! 1. Wir benutzen eine Schleife: double[] v2 = new double[ v.length ]; for ( int i=0 ; i<v.length ; i++ ) v2[i] = v[i]; Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 27 Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 29 1. Felder und Strings Mehrdimensionale Felder Mehrdimensionale Felder Mehrdimensionale Felder sind vom Prinzip her leicht zu definieren: Der Komponententyp ist selbst ein Feld. Beispiele: double[][] matrix; int[][] folgeVonFolgen; String[][] listeVonStringListen; Sollen alle “inneren” Felder die gleiche Länge aufweisen, können wir wiederum den new-Operator in einfacher Weise verwenden: matrix = new double[3][4]; folgeVonFolgen = new int[3][50]; listeVonStringListen = new String[5][30]; Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 1. Felder und Strings 30 Mehrdimensionale Felder Beispiele für “innere” und “äußere” Feldlängen: • matrix.length liefert 3. • matrix[0].length liefert 4. • matrix[2].length liefert ebenfalls 4. Die “inneren” Felder können eine unterschiedliche Länge aufweisen. int[][] folgeVonFolgen = new int[3][]; for ( int i=0 ; i<folgeVonFolgen.length ; i++ ) folgeVonFolgen[i] = new int[10*(i+1)]; • folgeVonFolgen.length liefert 3. • folgeVonFolgen[0].length liefert 10. • folgeVonFolgen[2].length liefert 30. Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08 31