Samstag, 16. November 2013

Felder in Java

Wichtig für Smartphonebenutzer

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:

  1. public class Namensliste {
  2.         public static void main(String[] args) {
  3.                
  4.                 // Deklaration von Referenzen
  5.                 String[] vorname;
  6.                 String[] nachname;
  7.                 String[] geburtsdatum;
  8.                
  9.         }
  10. }

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:

  1. ...
  2. String [] geburtsdatum
  3. // Erzeugen der Felder
  4. vorname = new String[3];
  5. nachname = new String[3];
  6. geburtsdatum = new String[3];
  7. ...

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:

  1. byte b = 5;
  2. double[] feld;
  3. feld = new double[23 * b];

und

  1. double[] feld;
  2. feld = new double['e'];

Da unsere Felder alle die selbe Länge in unserem Programm haben, können wir es auch so schreiben:

  1. ...
  2. public static void main(String[] args) {
  3.                

  4. // Deklaration und initialisieren einer
  5.      // einfachen konstanten Variable
  6.      int index = 3;
  7.                
  8.      // Deklaration von Referenzen
  9.      String[] vorname;
  10.      String[] nachname;
  11.      String[] geburtsdatum;
  12.                
  13.      // Erzeugen der Felder
  14.      vorname = new String[index];
  15.      nachname = new String[index];
  16.      geburtsdatum = new String[index];
  17.                
  18. }
  19. ...

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.

  1. ...
  2. public static void main(String[] args) {
  3.                
  4. // Deklaration und initialisieren einer
  5.      // einfachen konstanten Variable
  6.      int index = 3;
  7.                
  8.      // Deklaration von Referenzen
  9.      String[] vorname;
  10.      String[] nachname;
  11.      String[] geburtsdatum;
  12.                
  13.      // Erzeugen der Felder
  14.      vorname = new String[index];
  15.      nachname = new String[index];
  16.      geburtsdatum = new String[index];
  17.                
  18.      // Initalisierung der Felder
  19.      for(int i = 0; i < index; i++) {
  20.      vorname[i] = "leer";
  21.            nachname[i] = "leer";
  22.            geburtsdatum[i] = "leer";
  23.      }
  24.                
  25.      // Ausgabe auf der Konsole
  26.      for(int i = 0; i < index; i++) {
  27.      System.out.println("Vorname      : " + vorname[i]);
  28.      System.out.println("Nachname     : " + nachname[i]);
  29.      System.out.println("Geburtsdatum : " + geburtsdatum[i]);
  30.      System.out.println();
  31.     }
  32. }
  33. ...

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:

  1. int[] feld1 = {5, 6, 9, 7};
  2. double[] feld2 = {12.345, 12.43, -12.34455};
  3. 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:

  1. ...
  2.                
  3. // Wenn die Felder nicht gleich groß sind
  4. // wird eine Fehlermeldung ausgegeben.
  5. if (vorname.length != nachname.length ||
  6.         vorname.length != geburtsdatum.length) {
  7.         System.out.println("Achtung! Die Felder besitzen 
    nicht die gleiche länge.");
  8. }
  9. else {
  10.         // Initalisierung der Felder
  11.         for(int i = 0; i < vorname.length &&
  12.                        i < nachname.length &&
  13.                        i < geburtsdatum.length; i++) {
  14.                 vorname[i] = "leer";
  15.                 nachname[i] = "leer";
  16.                 geburtsdatum[i] = "leer";
  17.         }
  18.                
  19.         // Ausgabe auf der Konsole
  20.         for(int i = 0; i < vorname.length &&
  21.                        i < nachname.length &&
  22.                        i < geburtsdatum.length; i++) {
  23.             System.out.println("Vorname      : " + vorname[i]);
  24.             System.out.println("Nachname     : " + nachname[i]);
  25.             System.out.println("Geburtsdatum : " + geburtsdatum[i]);
  26.             System.out.println();
  27.         }
  28. }
  29.                
  30. ...

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:

  1. 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:

  1. for(int i = 0; i < feld1.length; i++) {
  2.         feld2[i] = feld1[i];
  3. }

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:

  1. 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:

  1. public class Namensliste {
  2.         public static void main(String[] args) {
  3.                
  4.                 // Deklaration eiens mehrdimensionalen Feldes
  5.                 String[][] liste;
  6.                
  7.                 // Erzeugen des mehrdimensionalen Feldes
  8.                 liste = new String[10][3];
  9.                
  10.                 for(int i = 0; i < liste.length; i++) {
  11.                    for(int t = 0; t < liste[i].length; t++) {
  12.                            // Initialisiere das                                                                  // mehrdimensionale Feld
  13.                            liste[i][t] = "leer";
  14.                    }
  15.                 }
  16.                                
  17.                 // Ausgabe auf der Konsole
  18.                 for(int i = 0; i < liste.length; i++) {
  19.                    for(int t = 0; t < liste[i].length; t++) {
  20.                          System.out.println("Vorname      : "                                                          + liste[i][t]);
  21.                          System.out.println("Nachname     : "                                                         + liste[i][t]);
  22.                          System.out.println("Geburtsdatum : "                                                          + liste[i][t]);
  23.                          System.out.println();
  24.                    }
  25.                 }
  26.                        
  27.         }
  28. }

Es hat sich einiges geändert und das Programm ist dabei sogar kleiner geworden.

Wir deklarieren unser mehrdimensionales Feld:

  1.                 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:

  1.                 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:

  1. ...
  2.                
  3. liste = new String[10][];
  4.                
  5. for (int i = 0; i < liste.length; i++) {
  6.         liste[i] = new String[3];
  7. }
  8.                
  9. ...

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":

  1. 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:

  1. int[][] feld = new int[3][];
  2. feld[0] = new int[6];
  3. feld[1] = new int[2];
  4. feld[2] = new int[9];

Hier werden 3 Felder erzeugt und jedes Feld wird mit einer andere Länge erzeugt.

Das Programm "Hallo Welt" in Ruby

Willkommen zum ersten Ruby Tutorial. Ich bin selber noch Anfänger in Ruby. Aber diese Programmiersprache hat mein Interesse geweckt und am besten lernt man wenn man es erklärt. So fangen wir mal an.

Erst sollte man sich Ruby herunterladen und installieren, auf dem Macinthos mit Mac OS X 10.2 ist es schon installiert. Auf Mac OS X 10.1 oder früherer Versionen, kann man Ruby leider nicht nutzen.

Zum Code schreiben brauchen wir nur ein Texteditor und die eine Eingabeaufforderung zum ausführen des Programms, das ist schon alles.

Wir wollen also dass unser erstes Programm "Hallo Welt" ausgibt.

Hier das Beispiel:

  1. puts "Hallo Welt"

Mit der Methode puts geben wir den String "Hallo Welt" auf den Bildschirm aus. Ein String steht immer zwischen einfache oder doppelte Anführungszeichen.

Jetzt erstellen wir und einen Ordner Hallo Welt. Danach speichern wir unser Programm unter HalloWelt.rb in den gerade erstellten Ordner ab. Dann öffnen wir die Eingabeaufforderung und wechsel in den Ordner.
Mit "ruby HalloWelt.rb" führen wir unser Programm aus.


Damit der Programmcode verständlicher ist, können im Programm Kommentare geschrieben werden. Mit # teilen wir dem Interpreter mit, dass der Text nach # ein Kommentar ist und der Zeile einfach übersprungen wird. Mehrzeiligen Kommentare stehen zwischen =begin und =end.

Hier ein Beispiel:

  1. # Dies ist ein einzeiliger Kommentar
  2.  
  3. puts "Hallo Welt"
  4.  
  5. =begin
  6. Dies ist ein
  7. mehrzeiliger
  8. Kommentar
  9. =end

Damit sind wir am Ende des ersten Ruby Tutorials. 

Dienstag, 5. November 2013

Wiederholungsanweisungen in Java

Wichtig für Smartphonebenutzer

Mit den Wiederholungsanweisungen können Anweisungen oder Anweisungsblöcke mehrfach hintereinander ausgeführt werden.

Die for-Anweisung
Hier ein Beispiel:

  1. for(int i = 0; i < 10; i++) {
  2.         System.out.println(i);
  3. }

In der Zeile 1, in den beiden ( und ) steht die Initialisierung im Beispiel ist es:

int i = 0;

Dann folgt der Ausdruck:

i < 10;

und zum Schluss die Updateliste:

i++

Am Anfang der for-Anweisung müssen wir eine Initialisierung eines Datentyps machen, dass heißt wir müssen einen Datentyp deklarieren und mit einem Wert initialisieren (die Initialisierung wird nur einmal in der for-Anweisung ausgeführt). Hier im Beispiel ist es die Wert 0. Danach kommt der Ausdruck, hier ist es i < 10, es wird ein boolean Ergebnistyp erwartet. Solange der Ergebnistyp true ist (also i kleiner als 10 ist) wird die for-Anweisung wiederholt. In der Updateliste wird  i inkrementiert. Unser Beispiel macht nichts anderes als von 0 bis 9 zu zählen. Dann ist der Ausdruck false und die for-Anweisung wird nicht mehr wiederholt.

Hier ist die Konsolenausgabe des Beispiels:


Wenn wie in unserem Beispiel nur eine Anweisung im Anweisungsblock steht, kann die { und } auch weggelassen werden. Die for-Anweisung verhält sich dabei wie die if-Anweisung. Es ist z.B. auch dieses möglich:

  1. for(int i = 0, t = 10; i < 10 && t > 0; i++, t--) {
  2.         System.out.println("Variable i = " + i);
  3.         System.out.println("Variable t = " + t);
  4. }

Es ist also auch möglich mehrere Variablen in der for-Anweisung  zu behandeln, sie müssen nur durch ein Komma in der Initialisierung und Updateliste getrennt werden. Im Ausdruck können die Logischen-Operatoren verwendet werden. Hier wird i inkrementiert und t dekrementiert.

Hier noch ein Beispiel:

  1. for(int i = 0, t = 10; i < 10; i += 2, t = t * 3) {
  2.         System.out.println("Variable i = " + i);
  3.         System.out.println("Variable t = " + t);
  4. }

Wie man sieht gibt es sehr viele Möglichkeiten bei der for-Anweisung. Hier werden die Variablen i und t deklariert und jeweils mit einem Wert initialisiert. Im Ausdruck wird aber nur die Variable i überprüft ob i kleiner ist als 10, wenn ja (also true), dann wird die for-Anweisung wiederholt. In der Updateliste wird Variable i mit 2 addiert und die Variable t mit 3 multipliziert.

Es ist auch möglich die for-Anweisungen ineinander zu verschachteln, hier ist noch ein weiteres Beispiel:

  1. for (int y = 0; y < 3; y++) {
  2.         for (int x = 0; x < 3; x++) {
  3.                 System.out.print((x + y) + " ");
  4.         }
  5.         System.out.println();
  6. } 

Die for-Anweisung in Zeile 1 wird ausgeführt, danach wird der Ausdruck auf den Ergebnistyp geprüft, wenn der Ergebnistyp true ist, wird die Variable y inkrementiert und der Anweisungsblock ausgeführt. Damit wird die for-Anweisung in Zeile 2 ausgeführt, die im Anweisungsblock steht und die Variable x wird inkrementiert. In Zeile 3 wird im Konsolenfenster die Summe von x und y ausgegeben. Die for-Anweisung von Zeile 2 wird wiederholt bis der Ergebnistyp im Ausdruck false ist. Mit System.out.println(); in Zeile 5 wird ein Zeilenumbruch erstellt. Jetzt wird die Variable y inkrementiert und die for-Anweisung aus Zeile 2 initialisiert x neu, die Variablen x und y werden addiert und deren Summe auf der Konsole ausgegeben. Jetzt wiederholt sich die for-Anweisung in Zeile 2 bis der Ergebnistyp im Ausdruck false ist. So geht es weiter bis die for-Anweisung in Zeile 1 auch der Ausdruck false erhält.

Hier die Konsolenausgabe:


Es gibt noch eine weitere vereinfachte for-Anweisung. Diese werden wir aber in einen späteren Tutorial besprechen, da uns dafür noch die Kenntnisse fehlen. Hier ein Beispiel:

  1. for(int i : t) {
  2.         ...
  3. }

Mit der for-Anweisung kann auch eine Endlosschleife erzeugt werden. Hier ein Beispiel:

  1. for(;;) {
  2.         ...
  3. }

Bei dieser for-Anweisung sollte immer eine  if-Anweisung mit einer break-Anweisung eingebaut sein, damit die Endlosschleife auch beendet werden kann. Eine switch-Anweisung ist hier leider nicht für das Beenden der for-Anweisung möglich.

Hier noch ein Beispiel:

  1. for(boolean b = true; b;) {
  2.         ...
  3. }

Diese for-Anweisung, ist auch eine Endlosschleife. Wir können diese Schleife beenden wenn wir eine Endscheidungsanweisung (if-Anweisung oder switch-Anweisung) einbauen die den Wert b false zuweist.

Die while-Anweisung


  1. int i = 0;
  2. while(i < 10) {
  3.         System.out.println(i++);
  4. }

In den ( und ) steht der Ausdruck der while-Anweisung. Wenn die while-Anweisung nur eine Anweisung hat, kann die { und } weggelassen werden. Der Ausdruck der while-Anweisung  erwartet den Ergebnistyp boolean, solange dieser Wert true ist, wird die Anweisung bzw. der Anweisungsblock wiederholt.

Auch bei der while-Anweisung, kann eine Endlosschleife geschrieben werden:

  1. while(true) {
  2.         ...
  3. }

Die while-Anweisung kann auch wie die for-Anweisung verschachtelt werden.

Die do-Anweisung


  1. int i = 10;
  2. do {
  3.         System.out.println(i--);
  4. } while(i > 0);

Bei der do-Anweisung wird zuerst die Anweisung bzw. der Anweisungsblock (der in { und } steht) ausgeführt und danach erst der Ausdruck der while-Anweisung ausgeführt. Die while-Anweisung muss hier mit dem Semikolon beendet werden.

Montag, 4. November 2013

Beneath a Steel Sky

Heute möchte ich das Point and Click Adventure "Beneath a Steel Sky" vorstellen.

"Beneath a Steel Sky" ist ein Science-Fiction-Triller, der in einer düsteren Zukunftsvision in Australien spielt. Man schlüpft in die Rolle von Robert Foster, der als kleiner Junge als einziger einen Helikopter-Absturz überlebte und von australischen Ureinwohnern aufgenommen und aufgezogen wurde. Eines Tages wird Foster durch ein Militärkommando aus der Stadt Union City verschleppt. Dabei wird seine Heimat und seine Freunde ausgelöscht.



Der Helikopter mit dem Foster entführt wurde, hat eine Fehlfunktion und stürzt über Union City ab. Foster ist jetzt auf der Flucht und muss sich durch die mit riesigen Industriekomplexen durchzogene Stadt in die Freiheit durcharbeiten.



"Beneath a Steel Sky" ist ein sehr spannendes Adventure, wenn man eine Zeit lang gespielt hat, möchte man einfach mehr über die Geheimnisse der Stadt Union City erfahren und warum Foster entführt wurde. Man sollte aber etwas vorsichtig sein in diesem Adventure kann man auch sterben wenn man was unüberlegtes macht.



Wer "Monkey Island" und "Baphomets Fluch" mochte, sollte sich das Spiel einmal anschauen. Neben der Ursprünglichen Fassung, die nicht mehr zum verkauf angeboten wird, gibt es "Beneath a Steel Sky" auch als Freeware und eine kostenpflichtige Version für iPhone und iPad.