# 1. Java-Grundlagen Das vorliegende Kapitel fast wesentliche Java Grundlagen zusammen, die im Laufe der Einführungsphase behandelt werden. Einige ausgewählte Themen wie Zeichenketten oder Felder werden im Rahmen der beiden Kapitel [Suchen und Sortieren](suchensortieren.md) sowie [Kryptologie](kryptologie.md) vertiefend aufgegriffen. ## Kontrollstrukturen Kontrollstrukturen beeinflussen des Verlauf eines Programms. Die nachfolgenden Beispiele sind an das Greenfoot-Szenario "Mars-Rover" angelehnt, können aber auch ohne Kenntnis des Szenarios nachvollzogen werden. ### Bedingte Anweisung Die bedingte Anweisung überprüft den Wahrheitswert einer Bedingung. Ist die Bedingung erfüllt, so wird der erste Anweisungsbock ausgeführt, ansonsten der zweite mit *else* gekennzeichnete Anweisungsblock. #### Zweiseitige Auswahl Werden beide Fälle aufgeführt, so sprechen wir von *zweiseitiger Auswahl*. ```java if (huegelVorhanden("vorne")) { drehe("rechts"); } else { fahre(); } ``` #### Einseitige Auswahl Verzichten wir auf den *else*-Fall, so sprechen wir von *einseitiger Auswahl*. ```java if (huegelVorhanden("vorne")) { drehe("rechts"); fahre(); } ``` #### Mehrseitige Auswahl Gibt es mehr als zwei gleichwertige Alternativen, so kommt entsprechend die *mehrseitige Auswahl* zur Anwendung. ```java if (huegelVorhanden("vorne")) { drehe("rechts"); } else if (huegelVorhanden("rechts")) { drehe("links"); } else { fahre(); } ``` #### switch-Anweisung Kann der weitere Verlauf vom Wert eines primitiven Datentyps oder vom Wert einer Zeichenkette abhängig gemacht werden, so steht als übersichtliche Alternative zur Mehrfachauswahl auch die switch-Anweisung bereit. Die *break*-Anweisungen sorgen dafür, dass der Programmablauf nach der Abarbeitung eines Falls nach der *switch*-Anweisung fortgesetzt wird. Der optionale *default*-Fall tritt ein, wenn keiner der vorherigen *case*-Fälle zutrifft. ```java switch (anzahlMeinerSchritte) { case 0: { fahre(); break; } case 1: { drehe("links"); break; } default: { drehe("rechts"); break; } } ``` ### Schleifen Zur wiederholten Ausführung einer oder mehrerer Anweisungen werden Schleifen verwendet. #### while-Schleife Die while-Schleife wiederholt eine oder mehrere Anweisungen so lange, bis eine gegebene Bedingung nicht mehr erfüllt ist. Da die Bedingung vor dem Anweisungsblock überprüft wird ("vorprüfende Schleife"), ist es möglich, dass der Anweisungsblock gar nicht ausgeführt wird. ```java while (!huegelVorhanden("vorne")) { fahre(); } ``` #### do-while-Schleife Die do-while-Schleife wiederholt eine oder mehrere Anweisungen so lange, bis eine gegebene Bedingung nicht mehr erfüllt ist. Da die Bedingung hier erst nach dem Anweisungsblock überprüft wird ("nachprüfende Schleife"), wird der Anweisungsblock mindestens einmal ausgeführt. ```java do { setzeMarke(); fahre(); } while (!huegelVorhanden("vorne")); ``` #### Zählschleife In der Zählschleife wird eine Zählvariable mit einem Anfangswert belegt. Der zugehörige Anweisungsblock wird solange ausgeführt wie eine Schleifenbedingung erfüllt ist. In der Regel wird diese Bedingung von der Zählvariable selbst abhängen. Zusätzlich wird durch die dritte Komponente des Schleifenkopfes die Zählvariable nach jedem Durchlauf verändert, d.h. meist um eins erhöht oder erniedrigt. Das folgende Beispiel sorgt dafür, dass die *fahre()*-Anweisung genau vier Mal ausgeführt wird: ```java for (int i=0; i<4; i++) { fahre(); } ``` ## Primitive Datentypen Im Unterricht verwenden wir die primitiven Datentypen *int*, *double*, *char* und *boolean*, die wir vereinfachend als ganze Zahlen, Kommazahlen, Buchstaben und Wahrheitswerte beschreiben. Datentyp | Wertebereich | Beispiele --- | --- | --- int | -2147483648 bis + 2147483647 | -1, 1 double | 4.9E-324 bis 1.8E308 | -3.14, 0, 6.28 char | alle Zeichen | 'A', 'Z' boolean | true, false | true, false ### Deklaration und Initialisierung Soll eine Variable eines primitiven Datentyps verwendet werden, so ist sie zunächst zu *deklarieren*, anschließend zu *initialisieren*, d.h. mit einem Anfangswert zu belegen. ```java int zahl; // Deklaration zahl = 0; // Initialisierung ``` Die beiden Schritte können auch kompakt zu einem zusammengefasst werden. ```java int zahl = 0; // Deklaration + Initialisierung ``` ### Vergleichsoperatoren Variablen des gleichen primitiven Datentyps lassen sich mit den Operatoren <, >, <=, >=, == und != vergleichen. Man beachte den Vergleichsoperator ==, der zur besseren Abgrenzung gegenüber dem Zuweisungssymbol = mit zwei Gleichheitszeichen geschrieben wird. ```java int zahl1 = 1; int zahl2 = 11; if (zahl1 < zahl2) { zahl1 = zahl1 + 10; } if (zahl1 == zahl2) { zahl1 = zahl1 + 100; } ``` ### Konvertieren von Datentypen Primitive Datentypen können ineinander konvertiert werden. In den meisten Fällen erfolgt die Konvertierung recht intuitiv - so wird eine double-Zahl in eine int-Zahl einfach durch Abschneiden der Nachkommastellen verwandelt. Die Verwandlung selbst wird durch den sogenannten *type cast*-Operator angezeigt, der den gewünschten Datentypen in Klammern vor die zu konvertierende Variable setzt: ```java double zahl = 1.47484; int zahl2 = (int) zahl; ``` Interessant ist die Verwandlung von Buchstaben (char) in ganze Zahlen (int) und umgekehrt. Dieser Transfer richtet sich nach der Nummerierung aller bekannten Zeichen gemäß der genormten ASCII-Tabelle (vgl. [Wikipedia-Artikel](https://de.wikipedia.org/wiki/American_Standard_Code_for_Information_Interchange)). Er weist beispielsweise dem Großbuchstaben A eine 65, B eine 66 usw. zu (Bildausschnitt aus [WikiPedia](https://commons.wikimedia.org/wiki/File:Ascii-codes-table.png)). ![](img/ascii.png) Diese Festlegung kann geschickt für Veränderungen von Buchstaben genutzt werden. Das folgende Beispiel etwa verschiebt den gegebenen Buchstaben H um vier Stellen im Alphabet. ```java char c = 'H'; int zahl = (int) c; zahl = zahl + 4; c = (char) zahl; ``` ## Klassen und Objekte ### Java-Klassengerüst Klassen werden in Java mit dem Schlüsselwort *class* eingeleitet. Bei der Modellierung einer Klasse wird festgehalten, welche Attribute (Eigenschaften) und Methoden (Anfragen oder Aufträge) für die Klasse sinnvoll sind. Im folgenden Beispiel wird für eine Klasse *Schueler* festgelegt, dass die Attribute Alter und Name verwendet werden. Beide bekommen durch den Konstruktor - eine besondere Methode mit dem gleichen Namen wie die Klasse - bei der Erzeugung eines Objekts der Klasse bereits saubere Anfangswerte. Zudem sind beide Attribute durch die beiden set-Methoden jederzeit veränderbar und die beiden get-Methoden jederzeit abfragbar. ```java public class Schueler { private String name; private int alter; public Schueler(String name, int alter) { this.name = name; this.alter = alter; } public void setName(String name) { this.name = name; } public String getName() { return name; } public void setAlter(int alter) { this.alter = alter; } public int getAlter() { return alter; } } ``` ### Erzeugen von Objekten Die Syntax zum Erzeugen eines Objekts sieht die Verwendung des Schlüsselworts *new* vor. Greifen wir das obige Beispiel der Klasse *Schueler* wieder auf, so müssen bei der Erzeugung eines Objekts der Klasse *Schueler* bereits Werte für die beiden Attribute übergeben werden. ```java Schueler s = new Schueler("Otto", 15); // Objekt erzeugen String z = s.getName(); // Namen abfragen int a = s.getAlter(); // Alter abfragen s.setAlter(a+1); // und neu besetzen ``` ### Vererbung Bei der Vererbung stehen der Unterklasse alle Attribute und Methoden der Oberklasse zur Verfügung. Auch der geerbte Konstruktor kann dabei zur Verwendung kommen. Im folgenden Beispiel wird einem Oberstufenschüler gegenüber einem Schüler zusätzlich das Attribut *Tutor* zugeordnet. Dieses Attribut kann hier zwar abgefragt, aber nach der Erzeugung nicht mehr verändert werden. Zusätzlich demonstriert diese Klasse mit der Methode *setName()*, wie eine Methode überschrieben werden kann, ohne die bestehende vererbte Methoden komplett neu gestalten zu müssen. Auch die Methode *erhoeheAlter()* ist geschickt gelöst, da das Alter erhöht wird, ohne direkt auf das Attribut *alter* zugreifen zu müssen. (*Bemerkung:* Eine Unterklasse kann nur dann direkt auf ein Attribut einer Oberklasse zugreifen, wenn die Sichtbarkeit des Attributs statt *private* auf *protected* gesetzt ist.) ```java public class Oberstufenschueler extends Schueler { private String tutor; public Oberstufenschueler(String name, int alter, String tutor) { super(name, alter); } public String getTutor() { return tutor; } public void setName(String name) { if (name.length()==0) { super.setName("unbekannt"); } else { super.setName(name); } } public void erhoeheAlter() { int alter = getAlter(); alter++; setAlter(alter); } } ``` ## Zeichenketten ![](img/string.png) Zeichenketten sind eine Aneinanderreihung von Zeichen, deren Anzahl beliebig ist. Eine Zeichenkette kann jederzeit verändert werden. In Java wird eine Zeichenkette durch ein Objekt der Klasse *String* repräsentiert. ### Durchlaufen einer Zeichenkette Um eine Zeichenkette mit einer Zählschleife zu durchlaufen, wird zunächst die Länge der Zeichenkette mit der Methode *length()* abgefragt. Die Zählschleife durchläuft nun die Positionen *0, 1, 2, ..., Länge-1* der Zeichenkette und greift per *charAt()* auf den i-ten Buchstaben zu. Die Nummerierung mit 0 beginnend ist anfangs ungewohnt, sie wird aber in Java konsequent auch in anderen Bereichen (z.B. bei Feldern) durchgeführt. ```java String eingabe = "TEST"; for (int i=0; i90) { zahl = zahl - 26; } char zeichen = (char) zahl; ergebnis = ergebnis + zeichen; } ``` ## Felder ![](img/feld.png) In einem Feld kann eine *beliebige, aber feste* Anzahl gleichartiger Elemente verwaltet werden. Die Anzahl der Elemente wird dabei beim Erzeugen des Felds festgelegt und kann anschließend nicht mehr verändert werden. Ungewohnt ist die Nummerierung der Elemente bei 0 beginnend und bei der Feldlänge-1 endend. Diese Form der Nummerierung findet in Java aber auch bei Zeichenketten konsequent Anwendung. Wir werden im Folgenden das Verwalten primitiver Datentypen (vgl. Zahlen im obigen Beispiel) in einem Feld betrachten. Das Speichern gleichartiger Objekte in einem Feld wird im Abschnitt [Felder](../zentralabitur/linear.md#feld) im Kapitel [Lineare Datenstrukturen](../zentralabitur/linear.md) behandelt. ### Erzeugen eines Felds Das folgende Beispiel zeigt zu Beginn die Syntax der Erzeugung eines Felds. Im Beispiel wird ein Feld der Länge 100 über int-Zahlen zunächst deklariert und anschließend initialisiert. Das Feld selbst ist aber zu diesem Zeitpunkt noch leer. ```java int[] meinfeld; // Deklaration meinfeld = new int[100]; // Initialisierung ``` Als abkürzende Schreibweise können Deklaration und Initialisierung wieder zusammengefasst werden. ```java int[] meinfeld = new int[100]; // Deklaration + Initialisierung ``` Folgt die geplante Besetzung des Felds einer festen Systematik, hilft eine Schleife bei der Besetzung der einzelnen Feldelemente. Im folgenden Beispiel werden die natürlichen Zahlen 1, 2, 3 usw. in das Feld eingewiesen. ```java // Erzeuge Feld int[] feld = new int[10]; // Besetze mit 1,2,3,... for (int i=0; i