Java Programmierung mit Datenstrukturen > Datenstrukturen in Java Mark Egloff 2006 1 Java Programmierung mit Lernziel Heute Abend > Sie lernen verschieden Datenstrukturen und Ihre Bedeutung kennen z.B. „Arrays, Listen, Bäume, Maps“ > Sie kennen die Unterschiede und wissen wann welche Datenstruktur vorteilhaft eingesetzt werden sollte > Sie können eigene Datenstrukturen erstellen, diese sortieren und entsprechend bearbeiten Mark Egloff 2006 2 Java Programmierung mit Datenstrukturen in Java Was sind „Datenstrukturen“? > Effiziente Algorithmen und Datenstrukturen bilden ein zentrales Thema der Informatik. Es haben sich mittlerweile Standards gebildet, die in allen Programmiersprachen vertreten sind. > In der Informatik bedeutet eine Datenstruktur eine bestimmte Art, Daten zu verwalten und zu verknüpfen. Daten werden dabei in einer bestimmten Struktur angeordnet um in geeigneter Weise darauf zuzugreifen und diese dann bearbeiten zu können. > Datenstrukturen sind immer auf einen Anwendungsbereich zugeschnitten, um den Zugriff und Manipulation entsprechend effizient zu gestalten und abhandeln zu können. Mark Egloff 2006 3 Java Programmierung mit Datenstrukturen in Java Übersicht Datenstrukturen > Arrays Mehrdimensionale Felder um Werte oder Objekte in einer festen Reihenfolge aufzunehmen. Die maximale Grösse ist festgelegt > Liste Die Liste ist eine Datenstruktur zur dynamischen Speicherung von beliebig vielen Objekten. Objekte werden dabei einer Reihe nach abgelegt > Bäume Mehrere Elemente können auf andere Elmente verweisen. So entstehen Verknüpfungen und es können „Bäume“ realisiert werden > Maps (Hashtabellen) „Maps“ sind Indexstrukturen, die die Elemente anhand eines Indexes oder Schlüssels verwalten Mark Egloff 2006 4 Java Programmierung mit Datenstrukturen in Java Übersicht Datenstrukturen in Java > Java kennt die meisten grundlegenden Datenstrukturen und bietet entsprechende Klassen und Hilfsklassen hierzu an. > „java.util.Arrays“ : Hilfsklasse zur Bearbeitung von Arrays > „java.util.Collection“: Basisklasse für alle Arten von Datenstrukturen > „java.util.Collections“: Hilfsklasse zur Bearbeitung von Strukturen > „java.util.List“: Basisklasse für alle Arten von Listen > „java.util.Set“: Basisklasse für alle Arten von sogenannten „Sets“ > „java.util.Map“: Basisklasse für alle Arten von indexierten Strukturen > Java kennt keine direkte Unterstützung für Bäume, hier müssen entsprechend eigene Klassen oder Klassen von Drittanbietern eingesetzt werden Mark Egloff 2006 5 Java Programmierung mit Datenstrukturen > Arrays in Java Mark Egloff 2006 6 Java Programmierung mit Datenstrukturen in Java Arrays > Ein Array (auch „Feld“ oder „Reihung“ genannt) ist ein spezieller Datentyp, der mehrere Werte zu einer Einheit zusammenfasst, die über einen ganzzahligen Index angesprochen werden können. > Er ist vergleichbar mit einem Setzkasten, in dem die Plätze durchnummeriert sind. Jeder Platz (etwa für Schlümpfe) nimmt immer Werte des gleichen Typs auf (nur Schlümpfe und keine Pokemons). > Die Grösse eines Arrays ist streng fixiert, sie wird bei der Erzeugung eines Arrays festgelegt. Normalerweise liegen die Plätze eines Arrays (seine Elemente) im Speicher hintereinander. Mark Egloff 2006 1 2 3 4 5 6 7 8 9 7 Java Programmierung mit Datenstrukturen in Java Arrays – Die Deklarierung > In Java gehören Arrays zum Grundsyntax der Sprache. Ein Array kann mit der einfachen Angabe durch „[]“ bei der Deklarierung einer Variable bzw. eines Objektes angegeben werden. > Die Angabe „[]“ kann nach dem Datentyp erfolgen oder nach dem Bezeichner, dies ergibt keinen Unterschied > Arrays können mehrdimensional sein. Hierbei wird für jede Dimension einfach eine entsprechende Dimension mit „[]“ angegeben. Syntax: Datentyp[] Datentyp bezeichner; bezeichner[][]; z.B: Deklarierung Arrays int[] aSimpleIntArray; Kreis[][] a2DCircleArray; Mark Egloff 2006 8 Java Programmierung mit Datenstrukturen in Java Arrays – Die Instanzierung (1/3) > Arrays werden in Java als komplexe Datentypen gehandhabt. Sie müssen nach der Deklarierung instanziert werden, bevor sie erstmals verwendet werden können. > Für die Instanzierung hat man zwei Möglichkeiten. Entweder mittels „new Typ[n]“ wird gleich die feste Grösse angegeben oder man gibt eine Aufzählung der Elemente an, mittels „{}“ und mit Komas getrennt. z.B: Instanzierung eines Arrays String[] wochentage = new String[7]; String[] laender; // keine Instanzierung nur Deklaration laender[0] = "CH"; Compilerfehler int[] primZahlen = { 1, 2, 3, 5, 7, 11 }; String[] substantive = {"Beware", "of", "the", "Dog"}; Mark Egloff 2006 9 Java Programmierung mit Datenstrukturen in Java Arrays – Die Instanzierung (2/3) > Arrays elementarer Datentypen werden bei der Instanzierung sofort mit Werten initialisiert (entweder mit 0 oder mit false bei boolean) > Bei komplexen Datentypen sind die einzelnen Positionen Referenzen, welche mit „null“ initialisiert sind. Diese Positionen müssen zuerst mit einem entsprechendem Objekt belegt werden. z.B: Deklarierung und Instanzierung eines Arrays m. komplexen Datentypen Kreis[] kArray = new Kreis[100]; System.out.println( kArray[20] ); // null kArray[20] = new Kreis(2.5f); System.out.println( kArray[20].getRadius() ); System.out.println( kArray[20] ); Mark Egloff 2006 // Kreis: radius = 2.5f 10 Java Programmierung mit Datenstrukturen in Java Arrays – Die Instanzierung (3/3) > Der Aufbau von zweidimensionalen Feldern ist vergleichbar mit einer Matrix beziehungsweise Tabelle. > Ebenso wie bei eindimensionalen Feldern lassen sich mehrdimensionale Felder gleich beim Anlegen initialisieren z.B: Deklarierung und Instanzierung eines multidimensionalen Arrays int[][] schachbrett = new int[8][8]; // Alle 64 Plätze sind 0 int[][] A3x2 = {{1,2}, {2,3}, {3,4}}; char[][] B232 = {{'A','B'}, {'C','D','E'}, {'F','G'}}; 1 2 A B 2 3 C D 3 4 F G System.out.print( A3x2[1][1]); // 3 E System.out.print( B232[1][2]); // E Mark Egloff 2006 11 Java Programmierung mit Datenstrukturen in Java Arrays – Zugriff auf die Elemente (1/2) > Der Zugriff auf die Elemente eines Felds erfolgt mit Hilfe der eckigen Klammern „[n]“ und einer int-Positionsnummer (Indexnummer), die hinter die Referenz an das Array-Objekt gesetzt werden. > In Java beginnt ein Array beim Index 0. Da die Elemente eines Arrays ab 0 nummeriert werden, ist der letzte gültige Index um 1 kleiner als die Länge des Felds. Bei einem Array a der Länge n ist der gültige Bereich somit a[0] bis a[n-1]. z.B: Zugriff auf ein Element im Array int[][] schachbrett = new int[8][8]; schachbrett[4][5] = 38; String[] substantive = {"Beware", "of", "the", "Dog"}; System.out.println( substantive[2] ); Mark Egloff 2006 "the" 12 Java Programmierung mit Datenstrukturen in Java Arrays – Zugriff auf die Elemente (2/2) Wird bei der Laufzeit über die Arraygrenze hinausgegriffen wird eine „IndexOutOfBoundsException“ erzeugt Wer bei einem nicht instanzierten Array auf ein Feld zugreift riskiert eine „NullPointerException“ z.B: Zugriff auf falschen Array Index und nicht initialisierter Array int[][] schachbrett = new int[8][8]; schachbrett[8][8] = 64; String[] substantive = null; System.out.println( substantive[2] ); Mark Egloff 2006 Laufzeit Fehler !!! Laufzeit Fehler !!! 13 Java Programmierung mit Datenstrukturen in Java Arrays – Die Länge eines Arrays ermitteln > Die Anzahl der Elemente, die ein Array aufnehmen kann, wird Größe beziehungsweise Länge genannt > Jedes Array-Objekt besitzt eine frei zugänglichen Objektvariable „length“ die abgefragt werden kann. „length“ ist eine public final int-Variable, deren Wert entweder positiv oder 0 ist. Die Größe lässt sich nach der Instanzierung nicht mehr ändern. z.B: Länge eines Arrays ermitteln int[] primZahlen = { 1, 2, 3, 5, 7, 11 }; System.out.println( primZahlen.length ); primZahlen.length = 100; primZahlen[primZahlen.length] = 11; Mark Egloff 2006 6 Compilerfehler Laufzeitfehler 14 Java Programmierung mit Datenstrukturen in Java Arrays – Iteration durch ein Array > Wer durch jeden Platz eines Arrays durchgehen (=iterieren) will, nimmt am besten die „for“ – Schleife. Auch hier gilt wieder Vorsicht mit dem ersten und letzten Index des Arrays. z.B: Iteration durch die Argumente der „main“ Methode public static void main( String[] args ) { for ( int i = 0; i < args.length; i++ ) System.out.println( args[i] ); } > Seit Java 1.5 gibt es eine vereinfachte Version der „for“-Schleife die speziell für die Iteration durch Datenstrukturen entworfen wurde for ( String arg : args ) System.out.println( arg ); Mark Egloff 2006 15 Java Programmierung mit Datenstrukturen in Java Arrays – Nicht „rechteckige“ Felder > Da in Java mehrdimensionale Arrays als Arrays von Arrays implementiert sind, müssen diese nicht zwingend rechteckig sein. Jede Zeile im Feld kann seine eigene Größe haben. > Die Abfrage jeder Reihen-Länge erfolgt mit „array[row].length“ z.B: Ein dreieckiges Array mit Zeilen der Länge 1, 2 und 3. int[][] m = new int[3][]; for ( int i = 0; i < 3; i++ ) m[i] = new int[i+1]; for ( int i = 0; i < m.length; i++ ) { for ( int j = 0; j < m[i].length; j++ ) System.out.print(m[i][j]); System.out.println(); 0 00 000 } Mark Egloff 2006 16 Java Programmierung mit Datenstrukturen in Java Arrays – String und Chars > Obwohl Strings in den meisten Programmiersprachen als einfache Character-Arrays angesehen werden, ist dies in Java nicht der Fall. char[] != String byte[] != String z.B. Folgende Zeile endet in Compilerfehler char[] s = "Java ist einfach!"; > Compilerfehler Java bietet bei der Stringklasse entsprechende Methoden an um in Arrays zu wandeln. z.B. String in char-Array wandeln und zurück z.B. String in byte-Array u. zurück String s = "Java ist einfach!"; char[] c = s.toCharArray(); String p = new String( c ); String s = "Java!"; byte[] b = s.getBytes(); String p = new String(b); Mark Egloff 2006 17 Java Programmierung mit Datenstrukturen in Java Arrays – Arrays sind Objekte > Arrays werden in Java als komplexe Datentypen angesehen. Sie werden selber wie Objekte handgehabt und es gelten somit die gleichen Gesetze für die Austauschbarkeit, das Kopieren und das Vergleichen z.B: Array als Objekt handhaben, Rückwärtskompatibilität u. Casting int[] iArray = {1,2,3,4,5}; Object i1 = iArray; Object[] i2 = iArray; Compilerfehler da int != Object Kreis[] Kreis Object Object[] k1 k2 k3 k4 = = = = new Kreis[20]; k1; Compilerfehler da Kreis[] != Kreis k1; k1; if (k3 instanceof Kreis[]) Kreis[] k5 = (Kreis[]) k3; Mark Egloff 2006 18 Java Programmierung mit Datenstrukturen in Java Arrays – Vergleichen eines Array > Da Arrays in Java wie Objekte gehandhabt werden können steht auch die „equals()“ Methode zur Verfügung („java.lang.Object“). Die Methode ist allerdings unbrauchbar da Sie nur die Referenzen vergleicht! > Um Arrays zu vergleichen, sollte man die statische Methode „equals()“ aus der Hilfsklasse „java.util.Arrays“ verwenden. Diese funktioniert auch für komplexe Datentypen richtig. z.B: Falsches und richtiges Vergleichen bei Arrays char[] abc1 = { 'a', 'b', 'c' }; char[] abc2 = { 'a', 'b', 'c' }; System.out.print( abc1.equals(abc2) ); false! System.out.print( Arrays.equals(abc1,abc2) ); true Mark Egloff 2006 19 Java Programmierung mit Datenstrukturen in Java Arrays – Klonen eines Array (1/6) > In Java können Arrays mittels der mitgelieferten „clone()“ Methode kopiert werden. Da die bekannte Methode „clone()“ den Datentyp „java.lang.Object“ zurückliefert ,muss nachträglich gecastet werden > Dieses Klonen funktioniert nur mit elementaren Datentypen. Bei Arrays mit komplexen Datentypen werden die einzelnen Feldinhalte nicht kopiert, sondern nur ihre Referenzen. Somit hat man mehrere Referenzen auf das gleiche Objekt z.B: Klonen eines int- Arrays int[] quelle = new int[ 6 ]; int[] ziel = ( int[] ) quelle.clone(); Mark Egloff 2006 20 Java Programmierung mit Datenstrukturen in Java Arrays – Klonen eines Array (2/6) > Eine alternative zu „clone()“ findet man bei der Klasse „java.lang.System“. Diese bietet eine statische Methode „arraycopy()“ an. Diese erlaubt noch zusätzlich von wo bis wo innerhalb des Arrays kopiert werden soll. > Dieses Klonen funktioniert auch hier nur mit elementaren Datentypen. Bei Arrays mit komplexen Datentypen werden nur die Referenzen kopiert z.B: Klonen eines int- Arrays mittels „System.arraycopy()“ int[] quelle = { 1, 2, 3, 4 , 5 }; int[] ziel = new int[ quelle.length ]; System.arraycopy(quelle, 0, ziel, 0, quelle.length-1); Mark Egloff 2006 21 Java Programmierung mit Datenstrukturen in Java Arrays – Klonen eines Array (3/6) z.B: Falsches Klonen eines Arrays mit komplexen Datentypen Kreis[] kArr = new Kreis[5]; for( int i=0; i<kArr.length ; i++) kArr[i] = new Kreis(i+1); Kreis[] kDup1 = kArr; kDup1[0] = new Kreis(3.0f); System.out.println( kArr[0].radius ); // jeder Platz m. Kreisobj // nur Kopie der Array Referenz // Kreis: radius=3 Kreis[] kDup2 = (Kreis[]) kArr.clone(); // Kopie aller Feldreferenzen kDup2[0].radius = 99; System.out.println( kArr[0].radius ); // Kreis: radius=99 System.out.println( kDup2[0].radius ); // Kreis: radius=99 Mark Egloff 2006 22 Java Programmierung mit Datenstrukturen in Java Arrays – Klonen eines Array (4/6) z.B: richtiges Klonen eines Arrays mit komplexen Datentypen Kreis[] kSrc = new Kreis[5]; for( int i=0; i<kSrc.length ; i++) kSrc[i] = new Kreis(i+1); // jeden Platz mit eigenem Kreisobj belegen ... Kreis[] kDest = new Kreis[kSrc.length]; // Klasse Kreis muss "clone()" Methode implementieren for( int i=0; i<kSrc.length ; i++) kDest[i] = (Kreis) kSrc[i].clone(); // jeden Platz kopieren Das Beispiel zeigt, dass das Klonen eines solchen Arrays umständlich ist. Deshalb zeigen die nächsten Folien wie man es generisch abhandeln könnte Mark Egloff 2006 23 Java Programmierung mit Datenstrukturen in Java Arrays – Klonen eines Array (5/6) z.B: generisches „deep“-Klonen eines Arrays mit komplexen Datentypen (1/2) public static Object[] cloneArray(Object[] arrSrc) throws Exception { Object[] arrDest = arrSrc.clone(); // kopiert "echten" Typ for( int i=0; i<arrSrc.length ; i++) { if (arrSrc[i] instanceof Cloneable ) { Class clazz = arrSrc[i].getClass(); java.lang.reflect.Method m = clazz.getMethod("clone"); arrDest[i] = m.invoke(arrSrc[i], null); } else throw new CloneNotSupportedException(clazz.toString()); } return arrDest; } Mark Egloff 2006 24 Java Programmierung mit Datenstrukturen in Java Arrays – Klonen eines Array (6/6) z.B: generisches „deep“-Klonen eines Arrays mit komplexen Datentypen (2/2) Kreis[] kSrc = new Kreis[5]; for( int i=0; i<kSrc.length ; i++) kSrc[i] = new Kreis(i+1); Kreis[] kClone = (Kreis[]) ArrayTools.cloneArray(kSrc); Andere Möglichkeiten des Kopierens: > Eine alternative für das herkömmliche Klonen/Kopieren ist mittels Objektserialisierung zu arbeiten. Hierbei werden Objekte in einen ByteStream geschrieben (z.B. als File) und dann wieder eingelesen. Somit entsteht eine Kopie ( Thema Serialisierung folgt später) > z.B. http://javatechniques.com/public/java/docs/basics/faster-deep-copy.html Mark Egloff 2006 25 Java Programmierung mit Datenstrukturen in Java Arrays – Die Hilfsklasse „java.util.Arrays“ (1/4) > Java bietet eine Hilfsklasse „java.util.Arrays“ an um die Handhabung der Arrays zu vereinfachen. Sie stellt Methoden für die Vergleichung, Stringwandelung, Initialisierung und Sortierung zur Verfügung (leider nicht für das Klonen) > Die Klasse besteht nur aus statischen Methoden, es muss daher kein Objekt von ihr instanziert werden. z.B: Sortieren eines String Arrays und String Ausgabe String[] sA = { "Java", "ist", "einfach!"}; Arrays.sort(sA); vorsicht, verändert Original System.out.println(sA); [Ljava.lang.String;@360be0 System.out.println( Arrays.toString(sA) ); [Java, einfach!, ist] Mark Egloff 2006 26 Java Programmierung mit Datenstrukturen in Java Arrays – Die Hilfsklasse „java.util.Arrays“ (2/4) Übersicht wichtigster Methoden > asList(a) konvertiert den Array in eine Liste (java.util.List) > binarySearch( a, b) Dursucht den Array bis der Wert gefunden wird und gibt Position zurück > deepEquals(a,b) Vergleicht zwei Arrays und jedes einzelne Element. Ist dabei das Element wiederum ein Array wird ebenfalls ein Vergleich durchgeführt > equals(a,b) Vergleicht zwei Arrays und jedes einzelne Element. Verwendet aber von jedem Element nur die „equals()“ Methode. Kein Vergleich v. Subarrays Mark Egloff 2006 27 Java Programmierung mit Datenstrukturen in Java Arrays – Die Hilfsklasse „java.util.Arrays“ (3/4) Übersicht wichtigster Methoden > fill(a,b) Füllt ein Array bzw. jeden Platz mit dem angegebenen Wert ab > sort(a) Sortiert die Elemente in einem Array. Kann auch für Objekte verwendet werden. Bei eigenen Objekten müsste aber zusätzlich das Interface „java.lang.Comparable“ in die Klasse implementiert werden > toString(a) Erzeugt aus dem Array eine String-Repräsentation. Es wird dabei von jedem Element die „toString()“ Methode aufgerufen. Mark Egloff 2006 28 Java Programmierung mit Datenstrukturen in Java Arrays – Die Hilfsklasse „java.util.Arrays“ (4/4) Elemente im Array suchen, „binarySearch()“ und „contains()“ > Ist das Array sortiert, lässt sich mit „Arrays.binarySearch()“ eine binäre Suche (Halbierungssuche) durchführen. Wenn das Feld unsortiert ist, funktioniert das nicht und die Java-Bibliothek hat für diesen Fall keine Funktion im Angebot eine eigene Schleife muss her. > Es gibt aber noch eine andere Möglichkeit. Die Funktion „Arrays.asList()“ dekoriert das Array als Liste vom Typ „java.util.List“, was dann eine „contains()“-Methode anbietet. z.B.: Teste, ob auf der Kommandozeile der Schalter „-?“ gesetzt ist: if ( Arrays.binSearch( args, "-?" ) >= 0) ... if ( Arrays.asList( args ).contains( "-?" ) ) ... Mark Egloff 2006 29 Java Programmierung mit Datenstrukturen in Java Arrays – Übergabe von Arrays bei Methoden > Arrays werde als komplexe Datentypen angesehen. Bei der Parameterübergabe wird demzufolge eine Referenz übergeben > Über die Referenz hat man Zugriff auf das Originalobjekt und kann deshalb den Original-Array verändern z.B.: Methode die den Original-Array verändert public static void toUpperCase( String[] sArray ) { for(int i = 0; i < sArray.length; i++ ) sArray[i] = sArray[i].toUpperCase(); } Mark Egloff 2006 30 Java Programmierung mit Datenstrukturen in Java Arrays – Methoden mit variabler Argumentanzahl > Seit Java 1.5 gibt es nun die „direkte“ Möglichkeit eine beliebige Anzahl von Parametern bei einer Methode zu übergeben. > Hierbei muss lediglich der Datentyp angegeben werden und mit „...“ abgekürzt. Der so übergeben Parameter funktioniert wie ein Array. > Ein Alternative hierzu wäre den Parameter als „java.lang.Object“ zu übergeben. Dieser Typ kann ja alles annehmen wie wir gesehen haben z.B.: Methode „max()“ mit beliebiger Anzahl an int-Argumenten : public static int max( int... iArray ) { int currentMax = Integer.MIN_VALUE; for ( int e : iArray ) if ( e > currentMax )currentMax = e; return currentMax; } Mark Egloff 2006 31 Java Programmierung mit Datenstrukturen in Java Arrays – Rückgabe von Arrays bei Methoden > Arrays können bei einer Methode zurückgegeben werden. Bei der Methodenrückgabe muss der entsprechende Datentyp angegeben werden z.B.: Produkt zweier Vektoren public static int[] prod( int[] a, int[] b ) { if (a.length != b.length) throw new IllegalArgumentException(...); int[] c = new int[ a.length ]; for(int i = 0; i < a.length; i++ ) c[i] = a[i] * b[i]; return c; } Mark Egloff 2006 32