Wir werden die verschiedenen Arten von Anweisungen

Werbung
Wir werden die verschiedenen Arten von Anweisungen nacheinander durchgehen und beginnen mit Variablendeklarationen. -­‐-­‐-­‐ Hier die Deklaration einer Variable namens klein m vom Typ int. -­‐-­‐-­‐ Und einer Variablen klein n, diesmal gleich mit Initialisierung. Die Variable n speichert den Wert 1. -­‐-­‐-­‐ Mit Schlüsselwort final wird aus der Variablen eine Konstante, das heißt, nach der Initialisierung darf der Wert von klein r nicht mehr verändert werden. Das werden wir später beim Thema Zuweisungen noch einmal sehen. -­‐-­‐-­‐ Die Deklaration einer Variable von einem Klassentyp sieht exakt genauso aus, hier eine Variable str1 der vordefinierten Klasse String. -­‐-­‐-­‐ Allerdings sieht die Initialisierung anders aus. Für weitere Erläuterungen siehe das Video zu Klassen und Objekten. -­‐-­‐-­‐ Deklaration einer Variable klein a, die auf einen Array mit Komponententyp double verweist. Auch zu Arrays gibt es ein eigenes Video. -­‐-­‐-­‐ Deklaration einer Arrayvariable klein b, die gleich initialisiert wird, nämlich als Verweis auf ein Array mit zehn Komponenten. -­‐-­‐-­‐ Das sind natürlich nur Beispiele, aber repräsentativ für alle auftretenden Fälle. -­‐-­‐-­‐ Welchen Wert hat eine Variable nun, wenn sie nicht sofort bei der Deklaration initialisiert wird? -­‐-­‐-­‐ In normalen Variablen, man nennt sie auch lokale Variable, kann irgendein beliebiger Wert stehen. Wir kommen gleich darauf zurück. -­‐-­‐-­‐ Konstanten, also mit Schlüsselwort final deklariert, muss man auf jeden Fall bei der Deklaration initialisieren. Denn später kann man den Wert ja nicht mehr setzen. -­‐-­‐-­‐ Wenn man ein Objekt einer Klasse einrichtet, aber nicht gleich dabei initialisiert, dann ist automatisch jedes Attribut mit dem sogenannten Nullwert seines Datentyps initialisiert. Und genauso sind bei Einrichtung eines Arrayobjekts alle Komponenten automatisch mit dem Nullwert des Komponententyps initialisiert. -­‐-­‐-­‐ Was ist dieser Nullwert? -­‐-­‐-­‐ Bei jedem Zahlentyp, egal ob ganzzahlig oder gebrochenzahlig, ist der Nullwert einfach die Zahl 0. -­‐-­‐-­‐ Der Datentyp char für Schriftzeichen ist ja im Prinzip ebenfalls ein Zahlentyp, nur dass der Zahlenwert eine spezielle Bedeutung hat, nämlich ein bestimmtes Schriftzeichen zu identifizieren. Auch hier ist der Nullwert die Zahl 0. Die Zahl 0 steht für kein Schriftzeichen. -­‐-­‐-­‐ Datentyp boolean hat ja nur zwei Werte, true und false. Der Nullwert ist false. -­‐-­‐-­‐ Für Klassen und Arrays gibt es einen symbolischen Nullwert, der durch das Literal null ausgedrückt wird. Eine ordentlich initialisierte Variable vom Klassen-­‐ oder Arraytyp verweist entweder auf ein Objekt, oder es hat den Wert null, eine dritte Möglichkeit gibt es nicht. -­‐-­‐-­‐ Noch einmal zurück zum undefinierten Wert von nichtinitialisierten lokalen Variablen. Bevor man eine solche Variable benutzt, muss man ihr unbedingt einen Wert zuweisen. Noch besser wäre eine Initialisierung. Aber das geht nicht immer, denn manchmal kennt man den Wert, den die Variable bekommen soll, nicht vorher. -­‐-­‐-­‐ Hier ein fiktives Beispiel. -­‐-­‐-­‐ Der Wert der nichtinitialisierten Variable klein n hängt von der Mondphase ab, die erst irgendwann später im Programm abgefragt wird. Die if-­‐Abfrage behandeln wir in diesem Video etwas später systematisch. -­‐-­‐-­‐ Bei abnehmendem Mond soll n den Wert 1 haben. -­‐-­‐-­‐ Und ansonsten den Wert 2. -­‐-­‐-­‐ Wichtig ist erstens, dass der Wert von n nicht vor dieser if-­‐Abfrage gelesen wird, da dann noch ein Zufallswert in n steht. Zweitens ist wichtig, dass n tatsächlich in jedem Fall auf einen Wert gesetzt wird, was durch den else-­‐Teil gewährleistet ist. -­‐-­‐-­‐ Nun zu einer anderen Art von Anweisungen, Zuweisungen. Als Beispielmaterial richten wir eine Variable klein m vom Typ int ein. -­‐-­‐-­‐ Die einfachste Art der Zuweisung, ein einzelner Wert. -­‐-­‐-­‐ Etwas komplizierter, aber immer noch im Prinzip dasselbe: Zugewiesen wird der Wert dieses mathematischen Ausdrucks, also 14. -­‐-­‐-­‐ In Java gibt es Kurzformen für den Fall, dass der Wert einer Zahlenvariable durch eine arithmetische Operation modifiziert werden soll. In diesem Beispiel wird der Wert von m durch Operator plus gleich um 5 erhöht. -­‐-­‐-­‐ Um 2 vermindert. -­‐-­‐-­‐ Nach Operator mal gleich steht in m das Sechsfache vom vorhergehenden Wert von m. -­‐-­‐-­‐ Und in diesem Beispiel wird der Wert von m durch 10 geteilt. -­‐-­‐-­‐ Wir hatten schon das Schlüsselwort final gesehen, mit dem eine Variable so wie hier zu einer Konstanten gemacht wird. Konstanten müssen immer initialisiert werden. -­‐-­‐-­‐ Das ist auch notwendig, denn die Konsequenz von final ist, dass nachträgliche Zuweisungen nicht erlaubt sind. Daher nennt man klein r eben Konstante statt Variable. -­‐-­‐-­‐ Wir betrachten noch einmal kurz Zuweisungen auch bei Variablen von Klassentypen. -­‐-­‐-­‐ Wir richten erst einmal zwei String-­‐Variable als Beispielmaterial ein: str1 ist initialisiert und verweist auf ein Stringobjekt, dessen Inhalt die Zeichenkette Hello World ist; str2 ist nicht explizit initialisiert und hat damit einen undefinierten Wert. -­‐-­‐-­‐ Erste Zuweisung, der Inhalt von str1 wird nach str2 kopiert. -­‐-­‐-­‐ Beide String-­‐Variable verweisen nun auf dasselbe String-­‐Objekt, eben das, mit dem str1 initialisiert wurde. Mehr zu diesem Thema gibt es im Video zur Referenzsemantik. -­‐-­‐-­‐ Zweite Zuweisung. Ab jetzt verweist str1 auf kein String-­‐Objekt mehr, sondern hat den symbolischen Wert null. -­‐-­‐-­‐ Damit schließen wir das Thema Zuweisungen ab. -­‐-­‐-­‐ Als nächstes betrachten wir die Rolle von Methodenaufrufe in Anweisungen. -­‐-­‐-­‐ Hier eine sehr einfache Beispielmethode. -­‐-­‐-­‐ Rückgabetyp ist int. -­‐-­‐-­‐ Daher kann diese Methode innerhalb eines arithmetischen Ausdrucks stehen, zum Beispiel so wie hier. Wir gehen davon aus, dass klein a eine Variable der Klasse ist, zu der die Methode gehört. -­‐-­‐-­‐ Der Wert des Parameters n ist in diesem Methodenaufruf 234 plus 423, also 657. -­‐-­‐-­‐ Diese 657 mal 2 und geteilt durch 3 ergibt 438. -­‐-­‐-­‐ Rechts vom Zuweisungszeichen steht daher 123 plus 438, also 561. -­‐-­‐-­‐ Auf diesen Wert 561 wird m gesetzt. -­‐-­‐-­‐ Nun eine leicht modifizierte Methode. Rückgabetyp ist void, es wird also nichts zurückgegeben. -­‐-­‐-­‐ Eine void-­‐Methode kann daher nicht Teil eines Ausdrucks sein. Aber der Aufruf einer void-­‐Methode ist für sich genommen schon eine Anweisung. -­‐-­‐-­‐ Wir schauen jetzt genauer auf die Return-­‐Anweisung in unserem ersten Beispiel. -­‐-­‐-­‐ Der Bezeichner klein n in der Return-­‐Anweisung ist der Parameter der Methode, also vom Typ int. -­‐-­‐-­‐ Daher ist der gesamte Ausdruck in der Return-­‐Anweisung vom Typ int. -­‐-­‐-­‐ So wie das int im Kopf der Methode es auch verlangt. -­‐-­‐-­‐ Das Schlüsselwort return sagt, dass der Wert des Ausdrucks hinter dem return der Wert ist, der durch den Methodenaufruf zurückzuliefern ist. Beispiel: Ist n gleich 100, dann wird der Wert 66 zurückgeliefert, weil 200 ganzzahlig mit Rest dividiert durch 3 gleich 66 ist. -­‐-­‐-­‐ Wir führen jetzt eine sehr wichtige Begriffsbildung ein, Rechtsausdrücke und Linksausdrücke. Die englischen Fachbegriffe sind etwas ungenau, rvalue und lvalue. Zuerst zu Rechtsausdrücken. -­‐-­‐-­‐ Ein paar illustrative Beispiele. -­‐-­‐-­‐ Ein illustratives, aber nicht besonders sinnreiches Beispiel für arithmetische Ausdrücke, in dem verschiedene Operatoren, ein paar implizite Konversionen und auch eine explizite Konversion vorkommen. -­‐-­‐-­‐ Ein sogenannter boolescher Ausdruck, also ein logischer Ausdruck oder anders gesagt ein Ausdruck vom Typ boolean. Die Variablen a und b sind vom Typ boolean. Also sind die Logikoperatoren anwendbar, und der Typ des Gesamtausdrucks ist ebenfalls boolean. -­‐-­‐-­‐ Bedingungen wie hier dieser Test auf Gleichheit liefern boolean zurück, dürfen also so wie hier Bestandteil eines booleschen Ausdrucks sein. -­‐-­‐-­‐ Der Aufruf einer Methode, die nicht void ist, ist ein Audruck. Der Typ des Ausdrucks ist der Rückgabetyp der Methode. -­‐-­‐-­‐ Auch der symbolische Wert null ist ein Rechtsausdruck. -­‐-­‐-­‐ Das alles sind Beispiele für Rechtsausdrücke. Jeder Rechtsausdruck hat einen Wert, und der ist von einem bestimmten Typ. -­‐-­‐-­‐ Rechtsausdrücke sind das, was auf der rechten Seite stehen darf. -­‐-­‐-­‐ Bei der Initialisierung einer Variablen. -­‐-­‐-­‐ Beziehungsweise später bei der Zuweisung eines Wertes an eine Variable. -­‐-­‐-­‐ Ein Rechtsausdruck ist aber auch das, was beim Methodenaufruf den Wert eines Parameters angibt. Das ist ja auch so etwas wie eine Zuweisung: Dieser Wert wird dem Parameter zugewiesen. Im Video zu Klassen und Objekten wird dieser Mechanismus unter Verwendung der Begriffe aktualer und formaler Parameter genauer erläutert. -­‐-­‐-­‐ Weiter sind Rechtsausdrücke auch genau das, was hinter einem return stehen darf. Auch das ist ja in einem gewissen Sinne eine Zuweisung: Der Wert des Ausdrucks hinter return wird der Rückgabe zugewiesen. -­‐-­‐-­‐ Schlussendlich sind Rechtsausdrücke auch das, was bei Arrays in eckigen Klammern stehen darf – bei der Einrichtung des Arrayobjektes zur Angabe der Größe des Arrays und wie hier zur Angabe eines Arrayindex. -­‐-­‐-­‐ Allerdings mit einer Einschränkung: Bei Arrays in eckigen Klammern muss der Typ des Rvalues int sein. -­‐-­‐-­‐ Damit sind die Rechtsausdrücke abgehakt, kommen wir nun zu den Linksausdrücken. -­‐-­‐-­‐ Analog sind Linksausdrücke das, was auf der linken Seite stehen darf. -­‐-­‐-­‐ Bei einer Initialisierung. -­‐-­‐-­‐ Beziehungsweise bei einer Zuweisung. -­‐-­‐-­‐ Das muss keine einzelne Variable sein, sondern kann beispielsweise auch eine Komponente eines Arrays sein. -­‐-­‐-­‐ Oder auch ein einzelnes Attribute eines Objekts von einer Klasse. -­‐-­‐-­‐ Allen diesen Beispielen gemeinsam ist, dass sie jeweils auf eine Speicherstelle verweisen, in der der zugewiesene Wert gespeichert werden soll. Wir schließen die Betrachtung von Rechts-­‐ und Linksausdrücken ab mit der Einsicht, dass jeder Lvalue ein Rvalue ist, aber nicht umgekehrt. -­‐-­‐-­‐ Und nun wenden wir uns den komplexen Anweisungsarten zu. Als erstes die if-­‐Abfrage. -­‐-­‐-­‐ Einstiegspunkt ist das Schlüsselwort if gefolgt von einem Ausdruck in Klammern. Das muss ein Logikausdruck sein, also vom Typ boolean. -­‐-­‐-­‐ Hier wieder das fiktive Beispiel von vorhin: Die Methode istAbnehmend von mond hat Rückgabetyp boolean und liefert true zurück genau dann, wenn der Mond im Moment des Aufrufs abnehmend ist. -­‐-­‐-­‐ In diesem Fall soll die int-­‐Variable klein m auf den Wert 1 gesetzt werden. -­‐-­‐-­‐ Ansonsten -­‐-­‐-­‐ soll die int-­‐Variable m auf den Wert 2 gesetzt werden. -­‐-­‐-­‐ Genau eine dieser beiden Zuweisungen wird durchlaufen. Danach ist klein m ein Indikator dafür, ob der Mond in diesem Moment abnehmend ist oder nicht. -­‐-­‐-­‐ Der else-­‐Teil muss nicht vorhanden sein. Ist kein else-­‐Teil vorhanden, dann werden keine Anweisungen ausgeführt, falls die Bedingung nach dem if nicht erfüllt ist. -­‐-­‐-­‐ Alle weiteren komplexen Anweisungen, die wir hier betrachten, sind Schleifen. Zuerst betrachten wir die while-­‐Schleife. -­‐-­‐-­‐ Eine while-­‐Schleife wird eingeleitet durch Schlüsselwort while, gefolgt von einem booleschen Ausdruck in Klammern. Das sieht sehr ähnlich wie der Kopf einer if-­‐Abfrage aus. Wichtig ist aber, dass eine Schleife etwas ganz anderes ist. -­‐-­‐-­‐ Stünde hier if und nicht while, dann würde die Anweisung m++ höchstens einmal ausgeführt. Aber while ist ein englisches Wort für solange, und genau das tut eine while-­‐
Schleife: Solange der Mond abnehmend ist, wird m um eins erhöht. -­‐-­‐-­‐ Das heißt, es ist ein Wechselspiel: Falls die Bedingung true ergibt, wird die Anweisung ausgeführt. Und dann wird sofort wieder die Bedingung getestet. Sobald die Bedingung zum ersten Mal false ergibt, ist die Schleife beendet. Falls die Bedingung schon beim allerersten Mal false ergibt, wird die Anweisung überhaupt nicht ausgeführt. -­‐-­‐-­‐ Die do-­‐while-­‐Schleife ist beinahe dasselbe wie die while-­‐ Schleife. Der semantische Unterschied ist, dass die Anweisungen im Schleifenrumpf unter allen Umständen mindestens einmal ausgeführt werden. -­‐-­‐-­‐ So sieht ein Beispiel aus analog zu dem Beispiel für while-­‐Schleifen von eben. -­‐-­‐-­‐ Rechts ist ein Programmstück zu sehen, das exakt dasselbe tut wie das Beispiel einer do-­‐
while-­‐Schleife links. -­‐-­‐-­‐ Es wird auf jeden Fall die Anweisung m++ mindestens einmal ausgeführt. -­‐-­‐-­‐ Im Gegensatz zur while-­‐Schleife wird erst danach die Bedingung zum ersten Mal getestet. -­‐-­‐-­‐ Von da an passiert dasselbe wie bei der while-­‐Schleife: Solange die Bedingung true ergibt, wird die Anweisung ausgeführt. -­‐-­‐-­‐ Damit ist die do-­‐while-­‐Schleife grundsätzlich vollständig erklärt. -­‐-­‐-­‐ Nun zur for-­‐Schleife. -­‐-­‐-­‐ Dies ist ein einfaches Beispiel einer for-­‐Schleife. Eingeleitet wird eine for-­‐Schleife durch Schlüsselwort for. -­‐-­‐-­‐ Gefolgt von einem Konstrukt in Klammern, das aus drei Teilen besteht. Die drei Teile werden durch zwei Semikolons voneinander getrennt. -­‐-­‐-­‐ Wie bei der do-­‐while-­‐Schleife erklären wir die for-­‐Schleife durch ein äquivalentes Programmstück mit while-­‐Schleife. -­‐-­‐-­‐ Der erste Teil im Kopf der for-­‐Schleife entspricht im rechten Programmstück einer einzelnen vorangestellten Anweisung. Das ist meistens, aber nicht zwangsläufig eine Variablendeklaration nebst Initialisierung wie hier. Auf eine kleine Diskrepanz gehen wir hier nicht weiter ein: Rechts ist die Variable klein i auch nach der while-­‐Schleife noch sichtbar; links ist i nur in der for-­‐Schleife sichtbar. -­‐-­‐-­‐ Der zweite Teil im Kopf der for-­‐Schleife entspricht der Bedingung der while-­‐Schleife. Man spricht auch von der Fortsetzungsbedingung der for-­‐Schleife. -­‐-­‐-­‐ Die Anweisung der for-­‐Schleife findet sich genauso auch in der while-­‐Schleife. -­‐-­‐-­‐ Aber dann kommt in der while-­‐Schleife noch eine weitere Anweisung dazu. Die ist identisch mit dem dritten Teil im Kopf der for-­‐Schleife. -­‐-­‐-­‐ Dieses Beispiel illustriert den Hauptzweck von for-­‐Schleifen: Man zählt eine Variable wie hier i hoch oder runter und tut in jedem Durchlauf irgendetwas mit dem aktuellen Wert von i. -­‐-­‐-­‐ In KarelJ gibt es noch eine weitere, einfachere Schleifenart, die es in Java so nicht gibt. -­‐-­‐-­‐ Die Semantik ist ganz simpel: eine gewisse Anzahl von Malen soll exakt dasselbe gemacht werden. In diesem Beispiel soll n-­‐mal der Wert von m um 1 hochgezählt werden. -­‐-­‐-­‐ Das kann man auch durch eine äquivalente for-­‐Schleife erklären. -­‐-­‐-­‐ Diese ganze for-­‐Schleife rechts ist nur dazu da, dass n-­‐mal dasselbe passiert. -­‐-­‐-­‐ Nämlich m um 1 hochzuzählen. Für diesen sehr speziellen, aber doch recht häufigen Fall ist die loop von KarelJ da, und in diesem Fall ist sie auch sehr praktisch. Leider nicht in Java. -­‐-­‐-­‐ Damit sind wir mit den Schleifen und insgesamt mit den Anweisungen fertig. 
Herunterladen