Mal wieder so ein paar Worte vorneweg.
Das passt immer ganz gut an dieser Stelle.
Das habe ich schon die letzten Jahre immer gemacht.
Wir haben auch jetzt in den ersten zwei Wochen schon ziemlich
viele Begriffe zugemutet in den Übungen oder auch in der Vorlesung.
Und dann kommen immer wieder so Fragen, ja,
warum heißen denn bei euch die Objekte, Exemplare,
wenn ich ein Buch lese, dann steht da mal was von Instanzen.
Was ist denn jetzt richtig und was ist falsch?
Oder andere sagen, die Dinger in den Objekten,
die die Zustände halten,
die heißen bei uns Zustandsfelder oder nur Felder oder vielleicht noch Exemplarvariablen.
Manche nennen die aber
auch Attribute
Was ist jetzt richtig und was ist falsch? Jetzt kann man
sagen, das ist ziemlich wichtig, weil richtige Begriffe.
Klar ist es uns wichtig, dass ihr die richtigen Dinge
richtig benennen könnt. Das ist auf jeden Fall wichtig.
Der gute Mark Twain hat das eher jetzt für Prosa formuliert,
dass das schon sehr, sehr deutlich Unterschied sein kann zwischen dem Wort,
was es gut trifft in dem Wort,
was es nicht ganz so gut trifft.
Aber das ist, wie gesagt, eher für Prosa.
Ich würde das ein bisschen in Frage stellen für das,
was wir hier machen. Eigentlich ist es fast egal,
wie wir die Dinge nennen. Natürlich ist es schön,
wenn wir Dinge so nennen wie der Rest der Welt auch,
damit wir hier nicht irgendwie in der Blase leben müssen.
Aber was viel wichtiger ist für das, was wir hier machen,
ist, dass wir versuchen die Begriffe konsistent zu verwenden.
Das heißt, ihr könnt davon ausgehen,
dass wenn wir einen Begriff hier einführen, dass wir ihn
auch konsistent in diesem Verständnis für den Rest des Semesters durchverwenden.
Das ist nicht immer so. Ich habe durchaus
Selbstveranstaltungen mitgemacht als Student. Da hatte ich das Gefühl,
dass da praktisch mit jedem Foliensatz wieder neue Begriffswelt eingeführt wurde.
Das ist bei uns anders. Wie gesagt,
wir bauen hier sehr konsequent auf einem Begriffsgebäude auf.
Deswegen ist es uns auch so wichtig, dass ihr bei
Schwierigkeiten mit der Unmenge anbegriffen, hier auch ein Glossar führt.
Da weisen wir immer wieder in Übungen drauf hin,
wenn irgendwie ich frage,
was ist denn das jetzt hier und woraus besteht denn so eine Klassendefinition,
was kann da so drinstehen im Rumpf einer Klasse und dann irgendwie erstmal leere Augen kommen,
dann ist es vielleicht nicht schlecht,
dass man die Dinge auch nochmal sich so ein bisschen anguckt.
Deswegen ist es auch wichtig, dass ihr euch das Skript
mal anseht. Das Skript ist nicht nur ausgeteilt,
damit ihr es irgendwie zu Hause in den Schrank stellen könnt.
Das wäre ziemlich sinnlos, sondern wir haben tatsächlich dieses Skript
jetzt auch als BDF endlich ins Komsi gestellt.
Hier ist Skript Level 1, also als PDF könnt ihr
dann auch in den Übungen nachschlagen.
Also wenn ich dann immer so in der Übung zu jemandem sage,
was ist das für ein Begriff, kannst du ihn denn nachschlagen?
Ja, am Skript hast du es dabei.
Nein, habe ich leider nicht dabei
Dann kann ich jetzt sagen, guck mal, im Komsi ist es ja auch.
Dann müsst ihr es nur eben aus dem Komsi rausholen,
dann kann man da eben durchbettern und zu der richtigen Folie kommen.
Weil eben halt viele Begriffe auch auf den Folien erklärt sind.
Auch noch ein kleiner Hinweis, hier ist nochmal der Hinweis von Irmo,
der ja die Bachelorarbeit über den Android-Client baut, für das Storesi.
Da wäre es toll, wenn sich da
möglichst viele Android-Nutzer bei ihm melden für die Pilotstudie.
Also bis jetzt war da ein bisschen wenig gekommen,
drückt euch das ja an, guckt eben kurz an,
was ihr dazu schreibt, dann das wäre sehr schön,
wenn wir da so 20 Leute zusammenkriegen würden.
Dann hatte ich letzte Woche mit dem Storesi hier so
eine Verständnisfrage gestellt, hatte diese ziemlich absurde Klassendefinition aufgelegt.
Das ist dann auch etwas, was sehr typisch ist für
so Informatikveranstaltungen, dass ihr irgendwann lernen müsst zu abstrahieren.
Bisher habe ich immer so versucht, möglichst anschauliche Klassen zu nehmen,
so was wie eine Klasse Konto und sich vorstellen kann,
einzahlen erhöht den Zustand und so weiter.
Das ist nun dummerweise hier so eine Klasse, die ist völlig sinnfrei.
Das heißt nur Klaas A besteht also nur aus der Mechanik von der Programmiersprache Java.
Man muss also wirklich sehen, was steht da und du
musst es verstehen können. Das ist aber so elementar,
dass wir das eben halt relativ früh von euch fordern,
dass ihr auch so was lesen könnt.
Es war relativ leicht zu beantworten, wie viele Zustandsfelder hier stehen.
Das haben fast alle richtig gehabt,
weil man die ja bei uns so gut erkennen kann.
Die haben ja so eine Konvention,
dass die bei uns mit dem Unterstrich benannt werden, einleitend.
Dadurch kann man die total leicht erkennen. Super. Dann
habe ich gefragt, wie viele Methoden. Na gut,
da haben schon mehr Leute irgendwie so gedacht,
es sind ja eigentlich drei Methoden sein,
weil die sind ja irgendwie so drei Dinger mit einem Rumpf,
ist es auch nicht.
Und außerdem habe ich auch gefragt, wie viele Konstrukturen.
Auch eine fiese Frage von mir, weil diese klassische Zweikonstrukturen hat.
Das hatte ich vorher gar nicht erklärt,
dass eine Klasse auch zwei Konstrukturen haben kann.
Aber ich hatte erklärt, dass der Konstruktor immer so heißt
wie die Klasse
Und keinen Ergebnistyp hat. Also konnte man hier sehen,
das müssen wohl irgendwie zwei Konstruktoren sein. Das heißt,
das sind so relativ einfache, sagen wir, Ableitungsschritte,
die wir euch da so ein bisschen abverlangen.
Und die braucht ihr aber auch. Sonst könnt ihr eigentlich
relativ schnell mit den Programmieren abschließen,
weil ihr müsst einfach diese Begriffe relativ schnell beherrschen und wissen,
wie ihr so eine Klassendefinition lesen könnt.
Gut, sehr schön, das nur zum letzten Mal.
Dann habe ich mal wieder hier das Storesi vorne.
Ich habe jetzt eigentlich gedacht, ich könnte jetzt auch mal testen,
wie viele Leute hören denn außerhalb dieses Hörsals zu über
den Livestream
Es werden vermutlich nicht so viele sein,
weil wir kein Internet haben, um den Livestream zu streamen.
Von daher ist es jetzt schon fast eigentlich ein bisschen hinfällig,
aber wir können es ja trotzdem mal machen.
Ich starte jetzt mal hier die Abstimmung und jetzt sammle mal wieder
so ein paar Stimmen, einfach um jetzt so mitzukriegen,
wie viele Leute sind jetzt ungefähr da?
Wie viele Leute sind jetzt aktiv beteiligt hier mit der Abstimmung?
Ich finde, also jetzt mit dem Clicker abstimmen,
gerät außerhalb des Hörsaals ist jedes Gerät.
Und wenn ihr im Hörsaal seid, dann ist das hier
ein bisschen differenziert. Also BC, D,
E und F ist für euch und A ist eigentlich für
die Zuhörer an den Bildschirmen draußen,
die jetzt nicht da sind.
Gut,
also hier jetzt
89 Stimmen, 198, okay. Also es sind mehr
als 200 Leute da, die auch teilnehmen.
Das ist ja schon mal ganz gut. Wir hatten letztes Mal
ein bisschen mehr. Da schauen wir mal. Cool,
ich beende das mal. Dann gucken wir mal ganz kurz
auf die Werte. Da gibt es ja keine richtige Antwort.
Ups, das war es nicht. Das war es.
Also 15 Prozent der Leute sind zumindest geistig abwesend.
Die sind nämlich auf einem Gerät außerhalb des Hörsals.
Sehr schön. Ja, wir sollten das ja auch nicht
übertreiben mit den sturisige Geschichten. Deswegen, das waren jetzt
nur zum Einstieg, damit ihr wieder warm seid.
Falls jemand noch, braucht jemand noch diesen Diesen Barcode hier, nein.
Ihr habt alle jetzt diese Adresse, entweder auch mit dem
Smartphone oder mit dem Laptop. Sehr schön. Das heißt,
zukünftig brauche ich da gar nicht mehr viel zu sagen.
Heute geht es um mit ein bisschen Verzögerung, um imperative Grundkonzepte.
Zum einen gucken wir uns den Prozedurbegriff an.
Was ist eine Prozedur? Wir nennen die hier bisher Methoden.
Auch das werdet ihr jetzt sozusagen unter einen Hut bringen müssen,
das bei uns mehrere Begriffe für dasselbe da sind.
In diesem Fall ist es so,
dass Prozeduren der imperativen Programmierung und Methoden relativ viel gemeinsam haben.
Und die Gemeinsamkeit gucken wir uns an.
Und im zweiten Teil gucken wir uns heute an,
wie das so aussieht mit dem syntaktischen Aufbau von Java-Programm.
Da kommen wir so ein bisschen so formale Grundlagen zur Syntax von Programmiersprachen.
Okay. Ja, Einstieg, was wir hier machen in
dieser Vorlesung ist ja, sagen wir, sehr geerdet loszugehen.
Das heißt, bei uns ist es so,
wir bringen euch Grundkonzepte der Programmierung bei, als Abstraktion oberhalb eines Rechners. Ja,
und fast alle Computer heutzutage funktioniert nach dem mein Schema,
also das ist die von Neumann-Architektur, die ist hier kurz umrissen,
das ist sehr viel ausführlicher dargestellt in der Vorlesungsrechnerstrukturen,
für diejenigen von euch, die die besuchen.
Für alle anderen ist das hier nur so ein kurzer Abriss,
also letztendlich besteht so ein Computer konzeptuell aus mehreren Werken,
also einer CPU, auf der das Leitwerk ist und das Rechenwerk,
das sind sozusagen die zentralen Einheiten eines Rechners,
dann gibt es ein Ausgabewerk,
das ist dafür da Ein- und Ausgaben über den auf den Hauptspeicher zu regeln.
Das heißt, der Hauptspeicher ist das Speicherwerk,
ist das vierte Werk und in dem Hauptspeicher
stehen eigentlich alle Daten und auch alle Programme
Die Besonderheit von Neumann. Früher war das anders,
da standen nur die Daten im Speicher, in einem veränderbaren
Speicher und die Befehle waren fest eingebrannt in die Computer.
Das ist lange vorbei. Dann ist dieser Hauptspeicher auch in Zellen
gleicher Größe unterteilt. Also das könnt ihr euch hier vorstellen,
das ist eine ziemlich lange Folge von Zellen,
in die dann Werte gespeichert werden können.
Und auch das Programm, das ausgeführt wird, steht in diesem Speicher.
Üblicherweise hat man in der CPU sowas wie ein Programmzähler,
das ist nichts weiter als die Adresse der Speicherzelle,
in der der nächste Befehl steht
Und wenn deine Befehle ausgeführt wurde, wird einfach dieser Zähler
um eins erhöht und dann wird der nächste Befehl ausgeführt.
So wird eben sequenzielle Ausführung auf so einem Rechner realisiert,
in dem einfach immer wieder Befehle hier geholt werden aus dem Speicher.
Dann werden sie hier dekodiert, dann kann das dazu führen,
dass der Befehl für die Ausführung weitere Daten im Speicher manipuliert.
Und dann ist es vorbei und dann kommt der nächste Befehl.
Das ist der sogenannte Fetch-Execute-Zyklus von Neumann-Rechnern. Also erst den Befehl holen,
dann ausführen und eventuell nochmal auf den Speicher zugreifen. So,
das heißt also, es geht alles hier über diesen Bus
und das wird auch gerne als von Neumann-Flaschenhals bezeichnet,
weil da irgendwie, naja, das ist letztendlich das,
was die Geschwindigkeit auch beschränkt,
was da so rübergeht,
das legt es fest
Gut, und dann ist es tatsächlich so,
dass die innerhalb des Speichers hier Binärcodes verwendet werden,
das wisst ihr auch,
0 und 1 letztendlich in diesen Speicherzellen, stehen so,
ja, 8 oder 16 oder 32 oder 64 Bit,
die dann zusammengefasst werden zu einem Wort.
So, okay, was ich schon gesagt habe,
diese CPU führt Maschinenbefehle aus,
die einfach immer aus dem Speicher geholt werden,
dann dekodiert werden und ausgeführt werden.
Das heißt also, Befehle und Daten werden hin und her
übertragen und beziehungsweise werden übertragen oder werden Ergebnisse zurück übertragen.
Und wenn wir jetzt mit imperativen Programmiersprachen arbeiten,
dann abstrahieren wir davon
Das heißt, wir fassen Folgen von Maschinenbefehlen zusammen zu Anweisungen.
Das habt ihr jetzt schon im Programmtext gesehen,
also in der Methode Zeichnet, der Klasse Zeichner, mehrere Anweisungen stehen untereinander.
Wenn ihr so eine Anweisung euch vorstellt,
wie eine variable E vom Typ Int, da steht jetzt,
I ist gleich i plus 3. Das ist eine Zeile,
eine Anweisung, es passiert aber auf der von Neumann-Architektur mehr.
Erstmal muss der Befehl einmal hier geholt werden,
dann muss er dekodiert werden, dann steht da irgendwie,
aha, I soll neu zugewiesen werden, aber es soll der alte Wert von I erstmal besorgt werden.
Also muss dieser Befehl dafür sorgen,
die Speicherzelle II hier irgendwo im Speicher ausgelesen wird,
hier reingeholt wird, dann wird hier addiert im Rechenwerk,
drei, die drauf addiert und das wird dann wieder in der Speicherzelle für die Variable II gespeichert.
So funktioniert letztendlich diese von Neumann-Architektur. Das heißt also,
diese Variablen, die wir üblicherweise verwenden, die abstrahieren von solchen physischen Speicherplätzen im Speicher.
Gut. Üblicherweise ist es so, dass die Ablaufsteuerung so ist,
dass tatsächlich diese Befehle nacheinander abgearbeitet werden und von Durchsprungbefehle dann von dieser Reihenfolge abgewichen werden kann.
Das heißt also tatsächlich, wenn ich jetzt an die Befehle abarbeitet.
Jetzt stelle ich fest, ich will aber was anderes aussehen,
was ganz woanders steht, muss ich einfach nur den Befehlszähler mit der Adresse dieser neuen Befehlssequenz laden.
Und ab da kann es dann wieder sequenziell weitergehen.
Diese Sprungbefehle kennen wir auch nicht. Ein Go-To werden wir
auch noch drüber sprechen. Gibt es in Java nicht,
auf der Ebene von Programmiersprachen hier, auf der Ebene von Kontrollstrukturen kennen wir inzwischen die Sequenz.
Also einfach Anweisungen werden sequenziell ausgeführt. Fallunterscheidungen habt ihr möglicherweise
schon so ein bisschen gesehen. Die Wiederholung sehen wir uns
zukünftig noch an. Heute geht es um Methodenaufrufe.
Also tatsächlich das, was passiert, wenn so eine Methode
in einem objektnotierten System aufgerufen wird
Die greifen ja auch in diesen sequenziellen Ablauf ein.
Wenn ich da jetzt irgendwie in eine Methode irgendwie eine Anweisung habe,
die eine Methode eines anderen Objektes aufruft,
wird ja wirklich zu dem anderen Objekt hingesprungen.
Da wird was ausgeführt und dann kommt es zurück.
Das gucken wir uns ein bisschen genauer an. Ich habe
natürlich wieder meinen Blue Jay dabei und habe hier mal die
Musterlösung für die Aufgabe von der letzten Woche, dieser Zeichner.
Da solltet ihr einen Parameter einführen hier in der Methode Zeichne.
Das ist relativ unspektakulär mit dieser Farbe, die da übergeben wurde.
Also im String sollte hier die Wandfarbe verändert werden.
Das habt ihr gesehen, das habt ihr gemacht.
Langeweile, also schmeißen wir es mal raus
Ja, Sonne, Sonne, Sonne. So,
jetzt haben wir hier aber eine spannende Methode, die heißt zeichne Häuser.
Ja, also wenn wir das jetzt hier mal übersetzen,
dann habe ich hier diese Methode,
zeichne Häuser und die zeichnet hier jetzt drei Häuser.
Also drei Häuser nebeneinander und nur eine Sonne.
Das sieht man auch hier, hier ist an der Schnittstelle
nur eine Methode Zeichen der Häuser.
Das liegt daran, weil tatsächlich nur diese Methode hier public ist.
Nur die gehört zur Schnittstelle, der Klasse Zeichner.
Hier haben wir
weitere Methoden
Die dann da aufgerufen werden. Und da sieht man jetzt genau,
was ich eigentlich jetzt hier auch zeigen will,
dass nämlich so Methoden aufrufe, Prozeduraufrufe sind.
Also hier diese Methode in einem Rumpf werden mehrere Sachen aufgerufen,
unter anderem hier zeichne Sonne, dann Zeichner Haus,
mit einer roten Wand zum Beispiel.
Und man sieht dann hier, Zeichner Haus bekommt also hier
eine Farbe und ein Offset übergeben. Das hier sind,
wie ihr wisst, die formalen Parameter,
die stehen im Kopf der Methode, die da aufgerufen wird.
Hier an der Aufrufstelle stehen jetzt aktuelle Parameter.
Man sieht hier dieselbe Methode wird dreimal aufgerufen mit verschiedenen
aktuellen Parametern
Und das führt dazu, dass tatsächlich dann auch diese Zeichenhausmethode sich dreimal anders verhält.
Deswegen kommt eben das erste Haus hier in das zweite da, das dritte dahin.
Das ist also parametrisierbar. Was mich ja auch noch so ein bisschen sehen ist,
wenn ich jetzt hier mir die Dokumentation anzeigen lasse,
dann hier funktioniert es, weil ich die neueste Blutlay-Version habe,
dann kann ich hier tatsächlich sehen bei Zeichen Häuser,
man kann es nicht sehen, ja genau.
Wir sehen also momentan in der Beschreibung nur die Schnittstelle.
Das heißt, wenn ich jetzt mal hier
die Sichtbarkeit von Zeichenhaus ändere auf Public und das übersetze,
ups, das wollte ich nicht, Steuerung K übersetzen.
Dann kann ich tatsächlich jetzt hier in der Dokumentation auch sehen,
dass so eine Methode auch gut dokumentiert sein kann,
nämlich in dieser Form hier Zeichnerhaus.
Hier ist der ganze Satz, der da beschrieben ist,
sein komplettes Haus. Farbe kann, der Auswand kann bestimmt werden.
Und hier entsprechend die Parameter mit Offset und Farbe.
Also das ist hier auch gut beschrieben.
Und das geht eben halt mit diesem Ad-Paran hier.
Also es gibt die Möglichkeit tatsächlich, das so gut zu beschreiben,
dass ein Klient das vernünftig benutzen kann. Gut. Ja,
und was wir dann auch hier weiter sehen, ist,
dass hier in Zeichen, Hauszeichen, eine Wand,
zeichnet, Dach aufgerufen wird.
Das sind wieder weitere Methoden, die innerhalb dieser Klasse hier zur Verfügung stehen.
Wieder mit Parametern, ja, formale Parameter.
Und hier stehen jeweils an der Aufrufstelle die aktuellen Parameter.
Das sind eigentlich die Begriffe, die wir uns heute nochmal genauer angucken wollen.
Und deswegen gehen wir hier mal rein. Ich habe schon gesagt,
die Methoden, die ihr so kennenlernt hier,
die sind so eine Spezialform des klassischen Imperativen Prozedurbegriffs.
Und in der imperativen Programmierung,
so wie in Sprache wie Pascal,
da sind Prozeduren
schon mit das mächtigste Abstraktionsmittel
Und vieles gilt halt analog. Und wir gucken uns jetzt erstmal
das Gemeinsamkeiten an, was so Prozeduren denn so ausmacht.
Zum einen können wir sagen, so Methodenaufrufe bestimmen letztendlich die Aktivitäten.
Wir haben schon gesehen, wenn irgendwie man eine Methode aufruft,
dann ruft die weitere Methoden auf. Also letztendlich ist die
ganze Programmausführung eine Folge von Aufrufen von Prozeduren oder Methoden.
Innerhalb einer Methode steht eigentlich immer so die Idee,
dass da fachlichen Algorithmus realisiert wird.
Das muss nicht immer ein Algorithmus sein,
das kann auch einfach irgendeine relativ einfache Abfolge sein.
Das ist relativ kühn, da immer von einem Algorithmus
zu reden
Algorithmen werden üblicherweise auch in eigenen Prozeduren gekapselt.
Software technisch haben wir schon gesehen, benannte Folge von Anweisungen.
Und die Idee ist einfach, dass so eine Methode dann
stellvertretend für diese Anweisungsfolge steht. Und man kann eben halt
das Verhalten noch so ein bisschen steuern, indem man Parameter übergibt.
Ja, hier nochmal so dieser Sache mit dem Algorithmusbegriff,
Algorithmus bildet aus problembezogener Sicht die kleinste Einheit beim Programmentwurf.
Also wenn ich irgendein Problem lösen will,
dann kann ich dafür
einen Algorithmus formulieren
Erster Zugang jetzt zu dem Begriff,
den wir nochmal ein bisschen genauer beleuchten, aber ganz ausführlich
werdet ihr über Algorithmen dann sprechen in Veranstaltungen wie Algorithmen und Datenstrukturen.
Aber letztendlich ist sein Algorithmus erstmal ein endlicher Text.
Ein Algorithmus ist auch üblicherweise Programmiersprachen unabhängig. Also ein endlicher Text,
der irgendeinen Lösungsverfahren beschreibt, das besteht aus mehreren Aktionen.
Was auch noch relativ wichtig ist,
dass so ein Algorithmus auch terminiert, also dass man irgendwie weiß,
dass er nicht nur aus einer endlichen Anzahl von Aktionsbeschreibungen besteht,
sondern auch nach endlich vielen Schritten,
wenn er ausgeführt wird,
auch seiner Bearbeitung beendet
Und wir können im Algorithmus einen Namen geben und das machen wir halt gerne in Prozeduren.
Also wenn wir sowas haben wie eine Anweisungsfolge hier, haben wir irgendeine Variablen Max.
Wir haben auch vermutlich irgendwelche Variablen A und B,
die hier vielleicht irgendwo vorher schon benutzt wurden, deklariert wurden.
Diese Anweisungsfolge betrachten wir einfach mal. Man sieht hier irgendwie zwei Varianten,
haben schon Werte, wenn A größer wäre,
es wird Max auf den Wert von A gesetzt.
Und wenn im anderen Fall wird Max auf die Wert von B
gesetzt. Das ist erstmal nur eine Anweisungsfolge. So,
und dann ist es eben halt schlau zu sagen,
naja, dann machen wir doch diese Dienstleistung,
diesen Mini-Algorithmus, machen wir doch zu einer Prozedur,
in dem wir der Anweisungsfolge einen Namen geben
Ja, und dann hier Parameter definieren,
formale Parameter und das Ganze dann aufrufbar machen. Das heißt,
ich kann jetzt an einer anderen Stelle als Klient dieses Dienstleisters auftreten und sagen,
brechen wir mir das Maximum von sechs und neun.
Das ist jetzt vielleicht nicht so ein spannendes Beispiel, ja.
Aber es können ja auch durchaus Variablen sein, die da irgendwie übergeben werden.
Gut, was wir jetzt hier schon gesehen haben, ist hier diese Parametrisierung.
Ich habe schon gesprochen über formale und aktuelle Parameter.
Ganz allgemein ist, die Möglichkeit, Prozeduraufrufe zu parametrisieren, sehr wichtig.
Da findet irgendwie eine Form von Datenaustausch statt. Das heißt,
der Klient ruft die Prozedur auf und übergibt irgendwelche Informationen.
Wir kennen hier bisher nur, dass wir Informationen reingeben.
Das ist auch in Java die einzige Möglichkeit,
da gehe ich gleich mehr dazu. Es kann aber durchaus
sein, dass da Daten auch zurückkommen über solche Parameter.
Wenn ihr wieder auf die von Neumann Architektur gucken,
dann sind das meistens Speicheradressen von Speicherzellen. Wenn man sagt,
also hier, ich übergebe dir mal einen Wert,
dann begibt man letztendlich die Adresse der Zelle,
wo dann
der Wert drinsteht
Gut, und ja, wir verwenden hier natürlich getypte formale Parameter in Java.
Das heißt, bei uns müssen die Parameter immer einen Typ hatten.
Zwei ganz zentrale Formen der Parameter, aber es gibt mehr.
Es gibt also in der Programmiersprachentheorie, ich glaube,
bis zu sechs Arten Parameter zu übergeben.
Einige sind sehr abgedreht. Die wichtigste ist die,
die ihr hier in Java kennenlernt.
Also die einzige, die Java hat. Java kann man
nur Werte hineingeben über Parameter. Also es gibt in Java
nur Eingabe bzw. Wertparameter
Das heißt, an der Stelle,
an der die Prozedur aufgerufen wird, also beim Klienten,
da stehen irgendwelche Ausdrücke,
die berechnen Werte und der Wert wird dann kopiert.
Und zwar den formalen Parametern zugewiesen der Prozedur, die da aufgerufen wird.
Das heißt also dann, die Werte dieser aktuellen Parameterausdrücke stehen
an der gerufenen Prozedur über diesem formalen Parameternamen zur Verfügung.
Gibt auch andere Möglichkeiten, Parameter zu handhaben?
Das sind sogenannte Ausgabe- oder Variabenparameter,
Call by Reference
Da kann tatsächlich dann ein Ergebnis geliefert werden. Da ist es dann tatsächlich so,
dass nicht nur irgendeinen Wert übergeben wird,
der da reinkopiert wird, sondern da wird tatsächlich gesagt,
du, liebe Prozedur, die ich dich jetzt gerade aufrufe,
ich gebe dir mal eine Adresse von der Zelle mit,
in der meine Variable steht.
Du kannst da was reinschreiben. Und wenn du fertig bist,
wenn die Prozedur wieder Aufruf zurückkehrt,
dann kann ich da in der Zelle nachgucken,
was diese Prozedur da reingeschrieben hat.
Das sind dann Ausgabe oder Variablenparameter, die gibt es in
Java nicht. Also falls es da Diskussionsbedarf gibt,
können wir in den Übungen gerne drüber sprechen.
Manche Leute glauben, dass es das gibt in Java,
aber das ist etwas anderes
Dann noch über Referenzen reden, die völlig anders funktionieren als das,
was hier gemeint ist, nämlich das Parameter auch etwas liefern können.
Ihr könnt eigentlich in Java nur etwas an den Aufrufer zurückliefern,
über die Möglichkeit, dass eine Methode einen Ergebnistyp hat,
wenn ihr euch hier dieses Beispiel mal anseht, das kennt ihr noch vom letzten Mal, Girokonto.
Hier habe ich mein Girokonto mit der üblichen Schnittstelle gekriegt,
einen Anfangssaal, da sagen wir mal 20 Euro sind da drauf,
dann wisst ihr hier jetzt Salto 20 und die Methoden kennt ihr auch schon,
einzahlen und gib Salto und bei Gibsaldo ist es dann tatsächlich so,
dass ich jetzt hier 20 rausbekomme und dass ich hier sagen kann,
in i ist gleich null,
aber so irgendwie eine Variable, jetzt kann ich schaden,
i ist gleich Giro Cont 1 gibt Saldo.
Und dann kann ich das tatsächlich mir jetzt hier,
dann wird der Aufruf durchgeführt, das Ergebnis wird dann zurückgeliefert,
das heißt, i bekommt dann am Ende diesen Welt.
Ich kann auch hier noch addieren, ich kann nur sagen,
ich will ausrechnen, wie viel Geld ich gerade habe,
ich habe irgendwie 100 Euro in Bar in der Tasche und gucke ich nochmal,
was auf meinem Giro Conto ist, das ist mein Gesamtvermögen.
Also hier, jetzt kann ich mir sagen,
wie viel habe ich denn in i120,
weil auf dem Giro Conto 20 drauf sind,
der Aufruf liefert das zurück,
es kann direkt in dem Ausdruck verwendet werden und wird
dann entsprechend hier addiert
Das ist die einzige Möglichkeit, wie etwas aus
einer Methode in Java rausbekommen könnt, über diesen Ergebnis-Typ.
Das ist ein sehr enger Kanal, nämlich nur ein einziges Element.
Gut, gucken wir uns nochmal diese Begriffe genauer an.
Das ist etwas, was hier in den Übungen,
wie gesagt, schon teilweise gesehen hat und auch gemacht hat.
Da haben wir auch schon nachgefragt. Wir haben hier unsere
Prozedur, unsere Methode Maximum. Die hat zwei formale Parameter
. Hier stehen die formalen Parameter im Kopf einer Methode.
Wir kennen formale Parameter daran, dass sie einen Namen haben.
Nicht jede aktuelle Parameter hat einen Namen
Da kann auch 100 stehen, 100 ist kein Name.
Aber bei den formalen Parametern muss es immer einen Namen geben.
Also hier A und B. Und die haben auch immer
einen Typ. Auch das ist etwas,
was gern falsch gemacht wird beim Programmieren, man anfängt,
dass man an der Stelle, wo man was übergibt,
irgendwie auch noch einen Typ dazu schreibt.
Lass das lieber sein. Aktuelle Parameter, da steht kein Typ dabei. So,
und das ist etwas, was der hier bekommen will,
dann kann er mit diesen Werten ja irgendwie rechnen und kann
dann irgendwie ein Ergebnis liefern auf Basis dieser Eingabewerte
Das sind hier die formalen Parameter. Jetzt habe ich verschiedene Aufrufende Stellen,
das kann tatsächlich ja ganz viele unterschiedliche Stellen geben,
wo ganz unterschiedliche Parameter, aktuelle Parameter übergeben werden.
Also hier irgendwie Ergebnis ist Maximum von 6,9,
dann ein anderer Aufruf, irgendwie Maximum von Ergebnis und zweimal X.
Und man sieht hier, dass tatsächlich dieser Aufruf möglich ist mit einem Ausdruck.
Ich kann also auch tatsächlich hier in BlueJ jetzt mit meiner tollen Klasse Zeichner,
ich habe hier meinen Zeichner,
jetzt zeig mir mal einen Zeichner und sage, hier,
Zeichner Haus, dann kann ich hier sagen,
blaue Wand.
Und hier sage ich
irgendwie 100 plus
Zwei. So, ja, das ist einfach ein Ausdruck,
den ich da angeben kann.
Das ist ein aktueller Parameter. An der Stelle,
wo der aktuelle Parameter steht, kann ich einen Ausdruck hinschreiben.
Und da wird doch tatsächlich irgendwas passieren. Also er malt da
ein Haus hin. Diese Position 120 mal zwei plus,
was weiß ich, irgendwo da. Das heißt,
das ist ganz wichtig, da, wo die Dienstleistungen aufgerufen wird,
also eine Methode oder die Prozedur, da können dann Ausdrücke stehen.
Und diese Ausdrücke nennen wir aktuelle Parameter.
Die müssen natürlich auch passen zu den Typen da oben.
Also wenn jetzt hier zum Beispiel steht zweimal X,
dann muss X eine Intvariabel sein oder irgendetwas kompatibel dazu ist,
damit das dann hier dem B zugewiesen werden kann.
Was ja auch vom Typ Int ist. Ich kann also
jetzt hier nicht an dieser Stelle irgendwie einen String übergeben.
Ich kann das auch mal vormachen hier, wenn ich jetzt
in der Klasse Zeichner mal versuche, zeichne Wandfarbe Offset.
Wenn ich jetzt hier sage, Farbe, zeichne Wandfarbe,
Farbe, dann übergebe ich ja als aktuelle Parameter zwei Strings.
Die Methode erwartet aber ein String und ein Int.
Wenn ich das jetzt übersetze, dann Gibt es einen Fehler.
Method zeichne Wand in Klaas Zeichner, Kennert be apply to given types,
required string, found, string, bam, bam, bam.
String int und einmal Stringstring. Genau. Also das ist einfach nützlich,
damit man sich, wenn man sich mal vertippt,
dann auch relativ schnell auf die Finger bekloppt bekommt, gekloppt bekommt.
Jetzt soll man das mal wieder korrigieren hier.
So, jetzt geht es auch wieder.
Okay, so viel zu den formalen und aktuellen Parametern.
Das hier sind dann die tatsächlichen aktuellen Parameter.
Klar, es gibt ja so ein paar Regeln.
Der Name der zu hofenden Prozedur beziehungsweise Methode wird überprüft,
ob das wirklich ein richtiger Name ist.
Es kann ja auch, ich kann ja auch jetzt anfangen
hier eine Methode aufzurufen, die es gar nicht gibt.
Ich kann ja jetzt auch noch mal sagen, zeichne Wandhalter.
Wird nicht funktionieren, weil diese Methode ist gar nicht da.
Das wird der Compiler auch meckern. Can out find Simble
, Method, zeichne Wandhalter. Klar, geht's nicht.
Also, zeichne Wand ist hier natürlich viel korrekter.
Anzahl der aktuellen Parameter muss gleich der Einzelne formal sein.
Das ist in Java so. Es gibt andere Sprachen.
Da kann man auch weniger Parameter angeben.
Hier ist es tatsächlich so in Java
Immer genauso viele Parameter angeben, wie der Dienstleister fordert.
Die Position ist auch festgelegt, auch das ist nicht immer in allen Sprachen so.
Und sie müssen ein Typ kompatibel sein. Es wird alles vom Compiler überprüft,
da könnt ihr euch schön zurücklehnen, das wird dann schon richtig gemacht.
Die Sache mit den Ergebnisprozeduren haben wir schon gesehen,
also Prozeduren, die ein Ergebnis liefern.
Das eine Beispiel, was ihr schon gesehen habt,
ist hier das Girokonto, hier diese Operation, diese Methode
Gib Saldo, die hat als Ergebnistyp ein Int und die
Dinger nennen wir Ergebnisprozeduren. Wir nennen die nicht Funktionen,
weil viele von euch vielleicht dann in der Schule gelernt haben,
es gibt Prozeduren, und es gibt Funktionen, Funktionen sind die,
die ein Ergebnis liefern, kann man so sehen.
Da sind wir wieder bei den Begriffen, die wir hier ja üblicherweise konsistent verwenden.
Eine Funktion sehen wir eher im mathematischen Sinne.
Es gibt tatsächlich auch in der Programmierung Funktionen,
die sich echt verhalten wie eine Funktion, als Seiteneffekt frei.
So etwas wie diese hier, da kann man nicht garantieren,
dass die nächste Seiteneffekt frei ist.
Also bloß weil die hier irgendetwas liefert,
es gibt auch durchaus Operationen und Methoden auf Objekten,
die Ende das Objekt und liefern etwas zurück.
Also von daher sprechen wir ungern von Funktionen im mathematischen Sinne.
Deswegen sagen wir dann Ergebnisprozeduren
Alles, was ungleich Void hat als Ergebnistyp,
ihr habt jetzt in den ersten Projekten immer gesehen,
dass da so diese Operationen auf diesen Figuren alle Void als Ergebnistyp hatten,
das hieß so viel, wie da kommt nichts zurück.
Aber wenn man da einen Inständen schreibt, wie in diesem Beispiel mit dem Saldo,
dann kann man eben halt auch das Ergebnis da rausbekommen.
Das habt ihr jetzt schon live gesehen. Gut,
das ist auch nochmal, wenn wir uns genauer angucken,
hier steht das formale Ergebnis, also tatsächlich Int ist das
formale Ergebnis dieser Prozedur oder Methode Maximum und an den Aufrufenden
Stellen kann man dann sozusagen diesen ganzen Ausdruck stellvertretend sehen für,
das hat diesen Typ Int,
das heißt also hier ist irgendein Ausdruck,
der vom Typ Int ist und der wird dann hier dieser Variablen zugewiesen.
Wenn eine Methode in Java hier einen Ergebnistyp anders als Void definiert,
dann muss auch da irgendwo ein entsprechender Wert geliefert werden.
Also das Return Max, da muss hier ein Ausdruck stehen,
der genau dazu passt, was da gefordert ist.
Also wenn da steht, diese Prozedur liefert einen Int,
da muss irgendwo im Rumpf auch sowas stehen wie,
das Ergebnis ist jetzt folgendes, zack, zurückgeben an den Aufrufer.
Okay, und dann,
wie gesagt, kann das da stellvertretend für das Ergebnis
gesehen werden
Jo, dann haben wir den Kontrollfluss. Wir haben schon gesagt,
dass wir ja in so einer Methode wie hier in dem Zeichner gesehen haben,
wie da so richtig schön sequenziell Dinge ausgeführt werden.
Also hier tatsächlich diese Operation, diese Methoden hier,
diese Methodenaufrufe, werden sequenziell ausgeführt.
Aber es passiert dann ein bisschen mehr. Ich kann das
ja vielleicht mal zeigen. Ich setze mal wieder einen Haltepunkt
hier rein und schließe das und dann doch mal sehen,
Wenn ich jetzt mir hier so einen Zeichner erzeuge,
dann kann ich ja mit diesem wunderbaren Debugger von Blue Jay so durchsteppen durch den Quelltext.
Also ich mache das hier mal ein bisschen schmaler,
damit wir ein bisschen mehr sehen.
Hier ist dieses Debugger-Fenster. Und da sieht man jetzt,
dass aufgerufen wurde, diese Methode Zeichnerhäuser.
Wir sind jetzt mitten in Zeichnerhäuser und der nächste Aufruf,
der jetzt ansteht, ist Zeichen der Sonne.
Jetzt kann ich hier das übliche Schritt übermachen. So,
und dann wird die Sonne da oben auch gezeichnet in
diesem anderen Fenster
Okay, das schiebe ich mal jetzt ein bisschen rüber,
das ist ja nicht ganz so wichtig.
Jetzt könnte ich hier auch nochmal einen Schritt übermachen und sagen,
zeichne mal das Haus und dann wird das Haus wirklich gezeichnet.
Ich kann aber jetzt tatsächlich auch in diesen Aufruf hineingehen,
das heißt, der Kontrollfluss wechselt ja jetzt hier aus der
sequenziellen Ausführung in diese Prozedur, die da aufgerufen wird, hinein.
Also tatsächlich in das Zeichen nach Haus hinein und das geht mit Schritt hinein.
Dann klicke ich jetzt hier hin und dann wird der tatsächlich in die Methode,
Zeichen nach Haus der Debugger hineinspringen und dann sieht man hier tatsächlich Zeichen nach Haus,
jetzt sind wir in der Sequenz,
in dem Rumpf dieser Methode
Und auch hier können wir jetzt wieder Schritt übermachen.
Oder auch Schritt hinein. Dann wird hier in Zeichen ein Dach hineingesprungen.
Und auch hier jetzt wieder sequenziell kann man jetzt diese Dinge ausführen.
Und dann wird das Dach da auch sichtbar gemacht. Und am Ende,
wenn ich am Ende so einer Folge bin hier,
dann, wenn ich jetzt nochmal Schritt mache,
dann wird er auch wieder dahin zurückspringen,
wo denn der Aufruf herkam.
Man sieht auch hier die Aufruffolge. Also wir haben zeichnet Häuser aufgerufen,
daraus wurde zeichnet Dach aufgerufen, Haus und dann zeichne Dach.
Wenn ich jetzt den Schritt hier mache,
dann wird er wieder zurückspringen ins Zeichen Haus.
Man seht ihr auch hier, dass dieses zeichnet Dach
jetzt abgeschlossen ist.
Also die Aufruffolge ist hier wieder reduziert
Ja, und auch wenn ich jetzt hier wieder Schritt übermache,
dann wird er da tatsächlich wieder nach Zeichen und Häuser
zurückspringen und dann kann ich hier jetzt nochmal das alles ausführen
und dann habe ich das ganze Haus gezeichnet.
Das heißt, das ist sehr schön mit dem Debugger auch nachzuvollziehen,
wie dieser Kontrollfluss funktioniert. Ihr solltet diese Möglichkeit dann auch nutzen,
das ist eigentlich ganz schön. Eine Prozedur ist aktiv,
nachdem sie aufgerufen wurde, also Prozeduren sind relativ langweilig,
wenn die so im Speicher hängen,
nur wenn sie aufgerufen werden,
dann werden die
richtig aktiv
Befindet sich immer in der Abarbeitung. Und auch wenn
dann aus dem Rumpf heraus eine weitere Methode aufgerufen wird,
bleibt die andere Methode ja noch aktiv.
Das ist also immer ganz wichtig, dass man sich klar ist,
dass dann eigentlich der Aufruf noch nicht zu Ende ist, die Ausführung.
Es wird nur zwischendurch was anderes gemacht und dann wird wieder zurückgesprungen.
Also wechselt dieser Kontrolle, diese Kontrolle beim Aufruf hier.
Da werden immer die aktuellen Parameter an die formalen gebunden,
ihnen zugewiesen. Prostituren können geschachtelt werden,
es entsteht eine Aufrufkette, haben wir jetzt alles live gesehen.
Nach der Abarbeitung der Prozedur kehrt die Kontrolle dann zum Rufer zurück.
Ja, und das ist auch nochmal hier so angedeutet.
Also hier mal wieder so ein völlig sinnfreies Beispiel,
irgendwie ein Stück Code
IF-Werte gegeben. Da wird irgendwie diese Bedingung ausgewählt,
nehmen wir mal an, diese Bedingung trifft zu.
Dann wird jetzt hier Volumen 1 gleich berechnet NR ausgewählt.
Da wird zuerst hier das Berechne ausgeführt. Das ist ein
Prozedur, ein Methodenaufruf. Hier ist irgendwo diese Prozedur berechnet
. Muss ja irgendwo sein, dass die Prozedur Definition,
so dann wird das hier der Kontrollfluss hinlaufen, in den Rumpf rein.
Am Ende wird das Ergebnis zurückgeliefert und dann wird das
hier tatsächlich in der variablen Volumen gespeichert.
Dann gibt es zum Elst, da sagt es natürlich,
okay, Werte waren gegeben,
also trifft das Elst nicht zu,
wir gehen drumherum
Und sind dann hier wieder im sequenziellen Ablauf. Das ist wieder
der Kontrollfluss und es ist eben halt wichtig, dass euch klar ist,
dass dieser Kontrollfluss bei diesen Prozeduraufrufen, bei diesen Methodenaufrufen wirklich wechselt.
Gut, dann zum Schluss dieses ersten Teils nochmal,
wir haben jetzt gesagt, dass ganz viel gemeinsam,
Prozeduren führen dazu, Prozeduraufrufe, dass der Kontrollfluss wechselt,
sind irgendwie Anweisungsfolgen, die zu einem Namen,
unter einem Namen zusammengefasst werden.
Parameter können übergeben werden, das ist alles bei allen möglichen Prozeduren,
sondern jeder Programmiersprache mehr oder weniger ist das so.
Die Methoden, habe ich ja gesagt, sind spezielle Prozeduren,
Das heißt, es kommt ein bisschen was dazu.
Zum einen ist es so eine Methode, gehört immer zu irgendeinem Objekt.
Das heißt, es gibt keine freistehenden Methoden,
die so einfach irgendwo hingeschrieben werden können. Ihr müsst immer
eine Methode in eine Klasse schreiben und damit ist klar,
dass die Methode immer auch zu den Exemplaren dieser Kasse dazugehört.
Und das führt dann automatisch auch dazu,
wenn ich so ein Objekt habe und die Methoden an dem Objekt ja drankleben,
das natürlich dann immer auch Zugriff ist auf die Felder des Objektes.
Das heißt, tatsächlich gibt es nicht nur die lokalen Variablen
für eine Methode und die Parameter, die übergeben werden,
sondern es gibt tatsächlich auch noch die Felder des Objektes,
an dem
das gerade ausgeführt wird
Und was ihr auch noch,
sagen wir jetzt hier in der Objektnotierung,
als sehr wichtig ansehen, ist diese Sichtbarkeit von Methoden,
also in Java, Private on Public.
Für uns heißt das erst mal Private, ist ein Detail der Klasse,
Public gehört zur Schnittstelle, ist also für Klienten aufrufbar.
Gut. Nochmal das, was ich gerade gesagt habe,
wir haben eigentlich jetzt drei Arten von Variablen kennengelernt.
Eine Variable hat einen Namen und einen Typ und während der
Ausführung gibt es eben halt auch eine Belegung für eine Variable.
Und wir kennen inzwischen drei Arten von Variablen, Exemplarvariablen,
formale Parameter und lokale Variablen.
Und hier haben wir nochmal so
ein Beispiel,
die Klasse Girokonto
Ich habe tatsächlich hier jetzt eine Exemplarvariable. Ich hoffe,
ihr erkennt das inzwischen, dass das eine Exemplarvariable ist.
Dann gibt es hier eine Methode und da jetzt auch einen formalen Parameter.
Und hier in der Methode gibt es eine lokale Variable,
die letztendlich hier nur zur Veranschaulichung verwendet wird und eingeführt wird.
Gut, gibt es zu diesen ganzen Begrifflichkeiten Fragen jetzt konkrete Fragen dazu.
Erstmal nicht, dann habe ich eine Frage.
Erstmal mache ich nochmal so eine kleine Zusammenfassung
Imperative Prozeduraufrufe. Das sind viel Methodenaufrufe, parametrisiert aktuelle Parameter
beim Aufrufe formale Parameter beim Dienstleister. Java kennt nur Wertparameter,
also tatsächlich arbeitet die gerufene Methode immer auf Kopien dessen,
was der Aufrufer da angibt. Ergebnis prozedurell liefern ein Ergebnis,
kontrollfloss wechselt und Methoden sind eben ein etwas reicheres Konzept.
Gut, kleine Verständnisfrage. Nehmen wir mal diese Klassendefinition hier,
mal wieder eine völlig sinnfreie Klassendefinition. Und ich frage mal
mit meinen Sturesi, Wie viele aktuelle Parameter enthält denn diese Methode?
Ich starte mal die Abstimmung und ihr könnt da jetzt sagen,
es ist ein aktueller, es sind zwei,
es sind 300, guckt euch das in Ruhe an.
Ihr müsst nicht sofort abstimmen. Überlegt einen Augenblick,
wie viele aktuelle Parameter enthält die Methode M?
Nachdem wir jetzt ja schon gehört haben,
es gibt aktuelle und formale
Ich warte so ein bisschen bis zu circa 200 Stimmen zusammen sind.
Es sollte ja drin sein. Der Empfänger blinkt immer noch
heftig. Es kommen immer noch Antworten rein.
Ja, ich glaube, das reicht dann auch.
Wir haben jetzt fast 200 Stimmen. Ja, wir haben
200 Stimmen. Sehr schön, ich stoppe das mal
Wir gucken mal, was das Abstimmungsverhalten ergeben hat. Ihr seht,
das ist relativ weit gestreut. Hier kommen tatsächlich viele Antworten,
die sagen, es ist nur ein aktueller Parameter.
Es gibt auch Leute, die sagen, es sind vier aktuelle Parameter.
Ziemlich viele sagen, es sind drei. Und die meisten sagen,
es sind zwei. Und das ist immer ganz beruhigend,
wenn zumindest die Mehrheit das Richtige sagt.
Also wenn ich das jetzt hier mal ausblende,
dann ist tatsächlich das die richtige Antwort
Ja, weil, das hier oben sind die formalen Parameter.
Es sind also drei formale Parameter. Das ist
der Ergebnis-Typ, der zählt überhaupt nicht als Parameter.
Das hier ist ein aktueller Parameter. Und das hier ist
ein weiterer aktueller Parameter. Das ist nämlich ein Ausdruck,
das sind zwar drei verschiedene Variablen, aber die bilden zusammen einen Ausdruck.
Und das ist ein aktueller Parameter. Das heißt,
diese Methode, die da aufgerufen hat, bekommt nur einen Parameter.
In diesem Fall also tatsächlich sind hier im ganzen Rumpf
zwei Stellen, an denen aktuelle Parameter begeben werden
Sehr schön, dann würde ich sagen, wenn jetzt nicht
Fragen dazu sind, dann machen wir fünf Minuten Pause.
Dann, ich würde jetzt nochmal hier drauf drücken.
Warum? Weil wir da nicht ganz rauchen können.
Okay, das ist aber nur eine Kleinigkeit.
Wenn ich jetzt drauf drücke, soll es er,
bitte Faden sagen, er will das erste jetzt nicht drücken.
Das ist ein guter Badewannen, genau. Das freut mich
erst letztens. Ich war auf der Fassung bei der Handelskammer,
da hat er das bitte warten und da stand zwei Stunden.
Alles klar, okay
Ganz kurze Frage, ganz kurze Frage, in die Runde.
Letztes Mal kam die Anregung, dass wir keine Pause machen sollten.
Ich würde gerne ein kurzes Meinungsbild sehen.
Wer ist dafür, dass wir eine 5-Minuten-Pause machen zwischendrin?
Wer ist eher dafür, dass wir keine Pause machen?
Das sind leider weniger, das sind leider weniger.
Ich habe es jetzt nicht mit dem Sturesi gemacht,
aber ihr könnt mir glauben, ich konnte das ganz gut erkennen.
Also es waren deutlich weniger. Also bleibt es bei einer Pause,
tut mir leid für diejenigen, die da jetzt die Pause ertragen müssen.
Gut. Ich hatte gesagt, es geht jetzt ein bisschen
um die Struktur von Klassendefinitionen, also wie sie aufgebaut sind.
Auch das habt ihr ja teilweise schon gesehen.
Was erstmal ganz wichtig ist, was ihr in Java,
wenn ihr jetzt so ein Editor öffnet, seht, das ist eine Klassendefinition.
Wir nennen die tatsächlich bewusst Klassendefinition, unterscheiden das von der Klasse.
Das heißt, wenn wir uns jetzt hier dieses Projekt angucken,
dann ist hier der Zeichner, ist die Klasse,
damit kann ich mir Exemplare erzeugen.
Das ist irgendwie sowas, was auch sozusagen zur Ausführungszeit irgendwie
eine Rolle spielt
Das basiert auf einer Klassendefinition. Das heißt,
diesen Text hier, diesen ganzen Text hier, dieses ganze,
ja, diesen Text, den bezeichnen wir als die Klassendefinition.
Und aus dieser Klassendefinition wird ja durch Übersetzung erst eine Klasse gemacht. Und diesen Vorgang,
den wir halt übersetzen, kompilieren, das werdet ihr,
wenn ihr programmiert, fast immer in irgendeiner Form haben.
Und was vielleicht auch nochmal ganz, was man sich wirklich klar machen muss,
es ist immer so ein bisschen so, ja, selbstverständlich möglicherweise,
aber das hier ist eigentlich nichts weiter als eine Folge von Zeichen.
Das heißt also, das geht hier oben los,
ja, und dann kann man hier wirklich so langsam durchkehren,
dass wieder eine Sequenz von Zeichen,
das ist hier zwar so ein bisschen zweidimensional dargestellt,
aber eigentlich ist es nur eine lange Folge vom Zeichen.
Eine lange Zeichenkette, kann man sagen. Das Ganze hier,
das ist eine Klassendefinition, die eigentlich nur aus Zeichen steht.
Und die Struktur, dass ihr sofort seht, naja,
das ist eine Methode, das ist zum einen,
weil wir Konventionen haben, wie die Dinge aufgeschrieben werden.
Zum anderen gibt es aber eben tatsächlich Regeln darüber,
wie sowas aufgebaut sein muss, damit es eine gültige Klassendefinition ist.
Und die gucken wir uns jetzt ein bisschen genauer an. Bisschen zum Hintergrund,
Java und auch Cishap zum Beispiel sind Hybride Sprachen,
das heißt, die haben einen Teil, Übersetzung,
das heißt, die Klassenebition wird übersetzt in einen Zwischencode.
Und dieser Zwischencode wird dann interpretiert. Es gibt auch Sprachen,
die machen das reinrassig,
also es gibt Sprachen wie die echte Compiler-Sprache sind,
C plus plus, da wird wirklich das Programm übersetzt und
dann hat man einen Object-Code und der ist dann spezifisch für eine bestimmte Plattform,
auf der kann dann dieses Ding ausgeführt werden.
Das ist so quasi Maschinencode. Es gibt auch Interpretersprachen,
sowas wie Lisp oder PHP, da ist es so,
dass dann tatsächlich die einzelnen Anweisungen jedes Mal neu übersetzt werden,
wenn sie ausgeführt werden müssen
Dann die Programmausführung dahin kommt, dann wird diese on the
fly ausgewertet und übersetzt und dann auch ausgeführt.
Das sind so zwei Seiten des Spektrums und wie gesagt,
Java und auch C. Sharp liegen da so in der Mitte.
Bei Java ist das eben tatsächlich so,
der Quelltext wird, habe ich schon gesagt,
in einen Zwischencode transformiert und der wird Java-Bytecode genannt.
Und dieser Zwischengrund wird dann der Virtual Machine übergeben.
Das heißt, wenn man sowas hat wie ein wie myprogramm.java,
dann läuft der Compiler los und macht daraus ein myprogramm.class.
Das kann man auch wieder sehr schön sehen hier
Hier in dieser Klasse Girokonten,
da sehen wir jetzt tatsächlich Girokonto.java und ich kann jetzt hier tatsächlich einen Doppelklick machen,
dann sagt er mir, hm, ich weiß gar nicht,
was das ist, dann sage ich,
ich lese nie mal eines der bekannten Programme,
da möchte ich jetzt aber das nicht dauerhaft verknüpfen und dann soll er mir das mal mit einem Editor aufmachen.
So, dann kann ich hier sagen,
Editor öffne mal das hier und dann habe ich einen ganz normalen Text-Editor,
wie ihn auch sonst von Computern kennt,
der das natürlich jetzt überhaupt nicht so schön anzeigt wie der Editor von Blue Jay,
also hier gibt es kein Highlighting,
da gibt es nicht irgendwie hervorgehobene reservierte Wörter oder ähnliches.
Auch hier ist es wieder so,
das ist nichts weiter als eine Folge von Zeichen
Einfach Sequenz von Zeichen. Was man aber auch sieht,
hier ist dieses Girokonto.klaas. Das heißt, das ist tatsächlich
so eine Klaas-Datei. Und das ist auch eine Folge von
nicht mehr Zeichen wirklich im Sinne von lesbaren Zeichen,
sondern das sind tatsächlich so binär kodierte Zeichen.
Bytes. Ich kann da auch mal einen Doppelklick draus machen.
Da würde er wieder sagen, kenne ich nicht, kann ich nicht.
Dann sage ich, ja, gib mir mal irgendwas hier,
nimm mal Wordpad. Nimm mal das da. Und dann
versucht er hier irgendwas anzuzeigen und es sieht ziemlich wild aus.
Das ist tatsächlich hier Zeichen Salat. Das liegt genau daran,
dass natürlich diese Struktur dessen, was da drinsteht,
schon irgendwie wohl definiert ist, aber dieser Editor nichts davon weiß,
der änderterweise überhaupt nicht, wie er das interpretieren soll.
Da kommen irgendwelche Bit-Folgen und er weiß nicht, wie er sie darzustellen,
sondern immerhin sieht man hier so Dinge wie Anfangssaldo,
Einzahlen, Betrag, aha,
also irgendwie steckt da wohl auch ein bisschen was im Klartext drin,
in so einer Glasdatei.
Aber die hat der Compiler tatsächlich erzeugt, diese Glasdatei.
Und das Schöne daran ist, dieses übersetzte Glasfall,
könnt ihr auf jedem Rechner laufen lassen,
auf dem eine Virtual Machine läuft.
Das ist die Besonderheit von Java, überall da,
wo eine Virtual Machine ist,
kann auch Java
ausgeführt werden
Once run anywhere, was damals versprochen wurde und was wirklich,
wirklich eingehalten wurde. Also mit Java kann man das erreichen.
Ich kann ein Programm schreiben und das auch tatsächlich übersetzen.
Und da muss ich, kann ich dieses übersetzte Programm auf jedem Rechner ausführen,
auf den ein solcher Interpreter läuft, eine Virtual Machine.
Das heißt, früher gab es irgendwie verschiedene Architekturen,
zum Beispiel die Mac-Welt hatte den Power-PC.
Windows hatte schon immer Intel-Prozessoren, irgendwann war Apple dann so
schlau, auch auf Intel zu wechseln. Das heißt,
die Architekturen sind gleich,
aber früher waren das verschiedene Befehlscodes auf der Ebene des Maschinencodes,
was ich eben so sagte,
diese Befehle auf der von Neumann-Architekturen
Oder Solaris, früher die Unix-Systeme, da war eben halt tatsächlich,
das waren verschiedene Architekturen, aber das war kein Problem,
weil es gab ja immer einen Interpreter, der diese Zwischenschicht darstellte.
Das ist ganz prima, ist inzwischen ein bisschen verwässert,
weil es Frameworks gibt, die wieder sehr plattform-spezifische Dinge tun,
aber für da war allgemein, für das,
was wir hier machen, gilt das auf jeden Fall noch.
Interessant dazu im Vergleich,.net, die Plattform von Microsoft,
auch so eine Zwischensprache, das heißt also,
Seasharp wird auch in diesen Zwischencode übersetzt.
Und da ist die Idee aber genau andersrum,
da wollten die möglichst viele Programmiersprachen haben, derselben Plattform.
Das heißt, es werden verschiedene Sprachen in diese Zwischensprache übersetzt.
Die Plattform ist dann Windows. Es gibt auch Portierungen für andere Systeme,
aber viele sprachen auf einer Plattform, während Java diesen Ansatz hat,
eine Sprache, ein Kompilat auf allen Plattformen.
Okay, was nur so ein bisschen zum Hintergrund,
ist ja wieder die Lupe dran.
Also das sind so Hintergrundinfos. Auch hier natürlich wieder
diese virtuelle Maschine ist sozusagen eine Abstraktion der von Neumann-Maschine dann
mit einem eigenen Befehlssatz, der dann eben wie,
wie gesagt,
einheitlich ist
Das heißt, man kann sich das so vorstellen, Hardware,
dann die Virtual Machine, die das so ein bisschen kapselt.
Dann gibt es die Java-API und die Dynastlava-Programm,
was ihr schreibt, sitzt da obendrauf.
Ja, genau. Und jetzt gucken wir uns mal ein
bisschen genauer an, wie die Struktur von Klassendefinitionen ist.
Ihr habt das schon so ein bisschen gesehen,
es gibt irgendwie innerhalb einer Klassendefinition im Rumpf einer Klassendefinition
können Zustandsfelder definiert werden oder Methoden oder Konstruktoren.
Wie die Dinger genau aufgebaut sein dürfen,
das ist üblicherweise beschrieben in einer formalen Notation.
Warum ist das eine formale Notation? Naja, das eine ist
der Computer muss ja sehr genau wissen, was er tun soll.
Das heißt, es muss eindeutig sein, was da steht.
Deswegen eine formale Notation. Hat aber auch den Vorteil,
dass wenn Menschen diese formale Notation verstehen, und das sollt ihr ja lernen,
dann könnt ihr auch verstehen, was das Programm tun soll.
Das ist also immer so dieses, was Programmiersprachen versuchen ist,
so irgendwie diese Brücke zu schlagen zwischen dem,
was ein Mensch gut versteht und dem,
was die Maschine gut versteht.
Das ist nach wie vor eine ziemliche Herausforderung. Gut,
dann gibt es gebräuchliche Darstellungsformen. Einmal die Bakkos-Nauerform,
beziehungsweise die erweiterte Bakkos-Nauerform,
die gucken wir uns kurz an,
so ein Tagsdiagramm auch nur ganz kurz
Dann als Hintergrund, wenn es also um Sprachen geht,
dann gibt es, weil auch bei natürlichen Sprachen,
Regeln dafür, wie vernünftige Sätze zu bilden sind.
Das sind üblicherweise die Syntaxregeln. Grammatikregeln,
wie ihr sie auch vielleicht in der Schule gelernt habt,
für Deutsch, aber auch für andere Sprachen.
Die Syntaxregeln sind zwar ziemlich klar, aber sie gelten auch
nicht immer durchgängig. Natürliche Sprache ist ja sehr viel flexibler.
Das, was wir machen mit formalen Sprachen hier,
mit Programmiersprachen, da ist es schon sehr festgelegt
Das ist das eine, also diese Regeln wie wohlgeformte Sätze aussehen sollen.
Was dann immer noch eine zweite Frage ist, was heißt denn
dann dieser Satz? Was soll denn dieser Satz aussagen?
Das ist üblicherweise die Semantik dessen, was da beschrieben wird.
Und das ist ganz allgemein in der Simiotik,
also in der Wissenschaft, der Zeichenverarbeitung, ist die Sematik,
die Lehre von der inhaltlichen Bedeutung einer Sprache.
Also was sagt denn ein bestimmter Satz aus?
Bezogen auf ein Programm ist es tatsächlich die Frage,
was macht das Programm? Zum einen im Speicher,
wenn es nur am Speicher irgendwie was verändert,
aber es gibt ja inzwischen auch Programme, Kernkraftwerke vorsteuern.
Und da muss man schon noch überlegen, was passiert eben
darüber hinaus. Nicht nur, was im Rechner passiert.
Das ist also tatsächlich der Effekt eines Programmes.
Und dann gibt es noch sowas wie die Pragmatik.
Das ist die Lehre vom Gebrauch einer Sprache in einem Zusammenhang.
Da kommen dann so Regeln hinzu, wie wenn man
das so benutzt, dann verstehen wir das so.
Das ist also durchaus über die Semantik hinaus. Ich gebe Beispiele
. Nehmen wir mal das hier sowas wie ein deutscher Satz.
Ein deutscher Satz wäre gebildet über Subjekt, Prädikatobjekt und Punkt dahinter.
Das kennt ihr ungefähr so als Damit kann man richtige deutsche Sätze formulieren.
Es gibt auch noch andere richtige deutsche Sätze,
aber das ist zumindest mal ein Bildungsgesetz hier.
Ein Beispiel ist dann hier, der Mann beißt den Hund.
So taktisch ist das korrekt, semantisch, interessant. Also üblicherweise beißen Hunde, Männer,
aber hier beißt eben halt mal der Mann den Hund,
gab und wie er die Welt sah von John Irving unbedingt mal lesen,
dann wisst ihr, dass sowas auch passieren kann,
dass Männer Hunde beißen.
Aber für uns heißt das erstmal nur,
Die Semantik ist halt was anderes, ja. Also insbesondere,
wenn ich jetzt hier sage, das Haus streichelt den Mann,
auch wieder Subjektprädikat, Objekt, syntaktisch, korrekt,
das ist aber ein ziemlich komischer Satz, ja.
Also spätestens da fragt man sich,
ob man vielleicht zu viel geraucht hat oder so.
Okay, aber... Unterschied zwischen Semantik und Pragmatik
kann man sich auch noch mal klar machen.
Also hier ist der Satz, da ist die Tür.
So, das hat eine klare Semantik irgendwie, da ist
die Tür. So, kommt aber ganz darauf an,
in welchem Kontext man diesen Satz jetzt ausspricht, ja.
Das kann zum einen so sein, irgendwie jemand fragt mich irgendwie,
entschuldigen Sie, können Sie mir sagen,
wo die Tür ist und als höfliche Antwort,
die Tür ist da,
da ist die Tür
So. Oder, irgendjemand regt mich rasend auf,
ich kriege hier schon den Herzkasper und sag jetzt,
jetzt aber raus, da ist die Tür, ja,
dann ist das eben eine ganz andere Pragmatik desselben Satzes.
Die Semantik ist die gleiche, aber die Wirkung,
der Effekt ist einfach nochmal ein bisschen was anderes.
Also Pragmatik muss man immer auch so ein bisschen mit dem
Spiel behalten, zieht sehr stark den Kontext mit ein.
Semantik sollte idealerweise kontextunabhängig klar sein. Das ist auch etwas,
was in der Programmiersprachentheorie sehr,
sehr viele Probleme bereitet
Aber da kommt ihr sicherlich auch nochmal in formalen Grundlagen der Informatik dazu.
Benutzerhandbücher geben oft Hinweise zur Pragmatik, sagen also nicht nur,
wie eine bestimmte Software zum Beispiel zu benutzen ist,
sondern auch, ah, wenn du besonders schlau sein willst,
dann machst du das da so und so und dann
kannst du da schneller da rüberkommen und so.
Also so pragmatische Hinweise oder auch Quelltextkonventionen.
Wir führen in dieser Woche jetzt in den Übungen Quelltextkonventionen ein,
also so, sagen wir, Konventionen, wie wir meinen,
dass der Quelltext, der in SE1 geschrieben wird,
aussehen sollte.
Das hat verschiedene Vorteile. Erstens lernt ihr da,
was solche Konventionen mal kennen.
Außerdem können wir leichter sehen, ob ihr auch das Richtige
gemacht habt
Und das sind auch nur Hinweise zur Pragmatik.
Da kommen wir jetzt auch noch mal drauf, dass nämlich
tatsächlich ich so eine Klasse ja sehr unterschiedlich hinschreiben kann.
Hier seht ihr mal so ein konkretes Beispiel, das kennt ihr schon,
ein Klargirokonto mit dem Feld Saldo und der Methode einzahlen.
Dann ist das hier so eine Art sehr simple Syntaxbeschreibung.
Hier so wird einfach gesagt, so eine Klassendefinition sieht folgendermaßen aus. Klaas,
dann kommt irgendein Klassenname, das ist ein Platzhalter hier mit
so einem spitzen Klammern, irgendwie immer Platzhalter,
dann kommen geschweifte Klammern und dann kann ich hinschreiben Felder,
Konstrukturen, Methoden.
Alles optional. Damit kann man schon viel anfangen.
Ihr würdet schon verstehen, was damit jetzt gemeint ist.
Ist aber sehr übervereinfacht
Das ist die Syntax. Dann gibt es sowas wie
die Semantik. Das heißt, diese Klasse hier,
da wissen wir, habe ich letzte Woche schon erzählt,
so eine Klasse hat auch einen Konstruktur,
weil wir schreiben keinen Konstrukte explizit hin.
Also, dann sagt die Sprache Java,
wenn kein Konstruktor da ist, dann nehme ich einen parameterlosen Konstruktor an.
Der ist tatsächlich dann auch da. Das heißt,
wenn ich da jetzt diese Klasse übersetze, dann hat hinterher diese Klasse einen Konstruktor.
Das ist tatsächlich eine Semantikregel von Java. Das ist etwas
, was tatsächlich einfach dazu definiert wird. Okay,
und dann Pragmatik ist die Sache mit der Reihenfolge.
Also wir sagen in unseren Quelltext-Konventionen gerne bitte zuerst die Felder,
dann die Konstruktoren,
dann die Methoden
Ist überhaupt nicht formal festgelegt. Ihr könnt die wild durcheinander
schreiben. Es hat die gleiche Wirkung. Das heißt,
das Programm ist davon gar nicht beeinflusst in dem, was es tut,
von dieser Reihenfolge, wie die Dinger da deklariert werden.
Es ist tatsächlich auch nicht so,
dass irgendwie erst etwas deklariert werden muss,
damit es dann weiter unten benutzt werden kann.
Ihr könnt auch eure Felder unten deklarieren.
Kein Problem. Das geht in Java. Nur,
dass es eben halt eine Frage der Pragmatik,
wie man die Dinger dann doch gerne da hingeschrieben hätte.
Aber hat nichts mit der Semantik
zu tun.
Jetzt gucken wir uns mal an, wie Programmiersprachen gerne beschrieben werden.
Also wie man die Syntax beschreibt. Nicht die Semantik.
Die Semantik von Sprachen ist ein richtig kompliziertes Thema.
Wir gucken uns erst mal an, wie kann ich denn syntaktisch
irgendwie möglichst exakt beschreiben, wie so eine Klassendefinition aussieht.
Dafür gibt es dann formale Grammatiken und die bestehen aus Grammatikregeln.
Das kennt ihr auch aus der deutschen Grammatik.
Und letztendlich geht es darum, dass man mit diesen Regeln
aus einem Staatssymbol richtige oder gültige Wörter ableiten kann.
Also sozusagen das, was man ableiten kann, wird ein
Wort genannt. Wie gesagt, den theoretischen Hintergrund dazu.
Das sind die kontextfreien Grammatiken aus der Trumpsky-Hierarchie.
Das ist nicht Thema dieser Veranstaltung
Das wird in den FGI-Modulen noch mal ein bisschen ausführlicher behandelt.
Aber als pragmatische Darstellungsform ist es eben halt sehr nützlich.
Also diese kontextfreien Grammatiken als Bakus-Nauer-Form,
kann man eben halt Programmiersprachen sehr schön damit beschreiben.
Also zumindest die Syntax. Hier so ein kurzer Hintergrund,
Bakus-Nauer-Form ist in den 50er Jahren entwickelt worden.
Und zwar gab es damals die Sprache Algollah, 58,
formale Beschreibung wurde von John Bakus vorgelegt.
Und dann hat ein gewisser Peter Nower diese Notation hergenommen
und modifiziert und dann zur Definition von Allgo 60 verwendet
Und seitdem ist diese Notation bekannt als die Bakus-Nauer-Form, BNF.
Also wo immer ihr diesen Begriff BNF seht,
wisst ihr, es kommt von Bakus-Nauer-Form.
Und das ist, wie gesagt, die häufigste Form der Syntax-Beschreibung.
Von Programmiersparen. Es ist interessant, dass tatsächlich schon vor Christus
Menschen versucht haben, Regeln festzuhalten über ihre eigene Sprache.
Das ist also nichts Neues. Das ist schon immer so gewesen.
Gut, Grundkonzepte der BNF, wir gucken uns die jetzt
mal an. Da sind zwei ganz zentrale Elemente,
nämlich Nicht-Terminale und Terminale
Nicht-Terminale sind so Platzhalter, wie wir sie eben schon gesehen haben.
Die werden oft in so spitzen Klammern notiert.
Also hier so eine Zuweisung. Wir wissen eine Zuweisung,
kann sehr unterschiedlich aussehen. Das ist also erstmal so ein Platzhalter.
Und dann gibt es Regeln zu so einem Nicht-Terminal.
Damit kann dann gesagt werden, wie so ein Nicht-Terminal aussehen kann.
Also zum Beispiel eine Zuweisung ist definiert über.
Das ist so ein Definitionssymbol, also eine Ableitungsregel.
Kann zum Beispiel aussehen, Bezeichner gleich Ausdruck.
Klar, es sieht eine Bezeichnung, eine Zuweisung aus,
wissen wir ja. Links steht ein Bezeichner, rechnet in
deinen Ausdruck
Von diesem Zuweisungssymbol. Das heißt, das Nicht-Terminal auf der
linken Seite von diesem roten Pfeil kann ersetzt werden durch das,
was auf der rechten Seite steht.
Links von diesem roten Falschen immer genau ein Nicht-Terminal.
Rechts können beliebig viele Nicht-Terminale und Terminale stehen. So,
und zu jedem Nicht-Terminal muss es auch tatsächlich eine Regel geben,
damit man irgendwie dann zu einem Ende kommt.
Gleich ist die Theorie vorbei. Also das andere ist ein
Diterminale. Also eine Programmiersprachgrammatik, das sind hier auch,
wenn auch häufig Lexime oder Token genannt.
Das sind die reservierten Wörter. Also wenn ich jetzt hier
in Java mir so einen Quelltext aufmache,
sowas wie New ist ein reserviertes Wort.
Das wird als ein Literal aufgefasst
Oder als ein reserviertes Wort, also ein Terminalsymbol, unteilbar.
Terminale sind sozusagen die kleinsten Einheiten in so einer Grammatik.
Also reservierte Wörter, dann Bezeichner,
also Namen von Variablen, Literale, Zahlen, 100,
200 und so weiter, Zeichenketten und Sonderzeichen.
Also größer, gleich, kleiner, gleich und so weiter.
Das sind Dinge, die sind sozusagen Grundbausteine so einer Sprache.
Und das sind die Terminale. Und die werden üblicherweise
oft tillen bei solchen BNF-Notationen so in einfachen Anführungsstrichen eingegeben.
Also hier sieht man zum Beispiel zwei Nicht-Terminale in dieser Regel
und ein Terminal
Die sind, wie gesagt, untalbar. Gut, und
dann haben wir schon praktisch alles, was wir wissen müssen.
Dann gibt es immer einen Nicht-Terminal, das ist das Staatssymbol.
Von da aus sind alle gültigen Wörter der Sprache ableitbar.
Also alle Sätze, also eigentlich korrekter alle Wörter, werden darauf abgeleitet.
Und die Elemente auf der rechten Seite an der Abgangsregel werden,
Konkatina, so einfach tatsächlich hintereinander gesteckt.
So, jetzt kann ich hier sowas haben, wie mehr als eine Definition.
Also ich habe zum Beispiel hier einen Nicht-Terminal-Zahl,
das sei definiert als entweder ein Intager oder ein Reel.
Das ist hier ein Oder. Diese roten Zeichen sind immer
Meta-Zeichen der BNF oder der EBNF
Also irgendwie so, ja, also nochmal wieder eine Ebene höher,
um zu sagen, das ist ein Sprachelement,
das dazwischen steht, dass zwei andere Sprachelemente trennt.
Oder man kann sowas auch rekursiv definieren. Rekursion werden wir
noch ein bisschen ansehen. Hier haben wir zum Beispiel eine Anweisungsfolge,
kann sein, entweder eine einzelne Anweisung oder,
das ist hier dieses Oder, es kann sein,
eine Anweisung, gefolgt von einem Semikolon, gefolgt von einer Anweisungsfolge.
So, und wenn ich jetzt versuche,
da jetzt diese Nicht-Terminale zu ersetzen, mit Hilfe von Regeln,
dann sehe ich hier Anweisungsfolge, oh,
dann habe ich doch wieder die Regeln,
gucke ich mal,
naja,
es kann seine Anweisung oder Anweisung
gefolgt von Anweisungsfolge
Kann ich da beliebig viele Anweisungen mit nämlich Kohlern getrennt definieren hier.
Das ist rekursiv definiert. Nehmen wir mal so ein Beispiel,
eine ganz einfache Syntaxbeschreibung, Zuweisung, sei definiert als Bezeichner, gleich Ausdruck.
Das ist hier diese Pascal-Notation für eine Zuweisung. Ein Bezeichner sei definiert,
kann entweder sein, ein Terminal A,
ein B oder ein C und ein Ausdruck kann sein,
ein Bezeichner plus einen Ausdruck, ein Bezeichner mal einen Ausdruck.
Es kann sein, ein geklammerter Ausdruck oder es kann einfach
nur ein Bezeichner sein. So, das ist eine sehr
kleine Grammatik und daraus kann man jetzt einiges an Wörtern ableiten.
Also ganz unterschiedliche Wörter. Wir nehmen mal ein Beispiel.
Ich kann also durch schrittweises Ersetzen jetzt dieser Nicht-Terminale und anwenden von
diesen Regeln, kann ich dann ein bestimmtes Wort ableiten.
Also nehmen wir mal hier die Zuweisung, da gibt es
nur eine Regel dafür, wir sehen nur eine Regel,
bezeichne gleich Ausdruck.
Gut, dann gucke ich mir den Bezeichner an, wie kann ich den ersetzen?
Ich kann den zum Beispiel durch ein A ersetzen.
Dann habe ich hier schon sozusagen A gleich,
jetzt muss ich nur noch sagen, was ist denn ein Ausdruck?
Na gut, ein Ausdruck kann sein,
jetzt haben wir hier ja mehrere Möglichkeiten und hier ist anscheinend die zweite gewählt,
also bezeichne mal Ausdruck.
So, und so geht es jetzt weiter.
Jetzt wird dann hier wieder der Bezeichner durch ein B ersetzt,
zum Beispiel an der Stelle
Der Ausdruck wird weiterersetzt durch einen geklammerten Ausdruck.
Und dann haben wir hier Bezeichner Plus-Ausdruck, also A plus
und dann der letzte Ausdruck, auch durch einen Bezeichner ersetzt.
Und dann wird man am Ende zum Beispiel diese Zuweisung,
A, ist gleich B, mal in Klammern A plus C.
Das ist ein Wort dieser Sprache. Das heißt,
das hier oben definiert eine Sprache, diese Grammatik.
Und das ist ein Wort. Jetzt gibt es aber
noch mehr Wörter, die man damit erzeugen kann.
Wie viele Wörter kann ich damit erzeugen mit dieser Sprache?
Ist das irgendwie abzählbar oder ist das Bild ihr so sagen,
was werft ihr mir so zu, wie viele Wörter sind das hier,
liegt damit dieser Grammatik erzeugen kann, wie viele verschiedene Zuweisungen.
Beliebig, genau, beliebig viele,
weil tatsächlich ja hier immer wieder ein weiterer Ausdruck,
also beim Ausdruck kann wieder ein Ausdruck da rankommen,
das heißt, ich kann das beliebig lang werden lassen.
Also beliebig lange Ausdrücke, die mit Mal und Plus geklammert sind.
Kann man hier bauen. So, dann gibt es die EBNF,
das ist die erweiterte Bakkus-Nauerform, die ist eigentlich genauso gebaut,
nur mit kleinen Erweiterungen, zum Beispiel diese Sache mit der Rekursion,
ist halt vielleicht für viele Menschen nicht so gut nachvollziehbar.
Also diese Idee, Anweisungsfolge ist definiert entweder über eine Anweisung
oder über eine Anweisung gefolgt von einer Anweisungsfolge,
kann man stattdessen auch schreiben, Anweisungsfolge ist eine Anweisung,
gefolgt von beliebig vielen Anweisungen.
Das heißt, diese geschweiften Klammern hier sagen, das,
was dazwischen steht, darf beliebig oft auftreten, auch nullmal, also gar nicht.
Also das ist auch eine einzelne Anweisung, eine Anweisungsfolge.
Dann gibt es noch die Möglichkeit, optionale Elemente,
also eine Anweisung kann sein, eine Zuweisung,
Prozeduraufruf und so weiter,
kann aber auch gar nichts davon sein,
weil das hier komplett mit dieser optionalen Klammer geklammert ist
Ja. Und dann gibt es als Alternative dazu auch Syntacdiagramme.
Die habt ihr vielleicht mal gesehen, wenn ihr mit Pascal programmiert habt.
Hier das gleiche Beispiel, eigentlich eine Zuweisung,
ist ein Bezeichner, Doppelpunkt, gleich Ausdruck.
Da sind die Terminale immer so in runden Dingern angegeben und
die Nicht-Terminale sind so Kästen. Dann weiß man immer,
na, wenn da so ein Kasten ist,
dann kann ich zum Beispiel, haben wir hier mal irgendwo angenommen,
Anweisungsfolge, ist definiert eine Anweisung und dann gefolgt von beliebig vielen Simikolas.
Da kann man sich also vorstellen, wie man hier sozusagen so durchlaufen kann.
Und die Anweisung hier, Ist dann genau optional eine von diesen Möglichkeiten.
Man kann sich also diesen ganzen Kasten hier da sozusagen reinsetzen.
Und dann wird da ein Riesengeflecht draußen,
kann man genau sehen, was für Möglichkeiten es gibt.
Sind nicht mehr so üblich, diese Syntaxdiagramme.
Aber die gab es früher relativ verbreitet. So,
jetzt haben wir, warum erzähle ich das alles hier?
Ich sehe so gelangweilte Gesichter hier, so ein Scheiß,
ey, was will der von mir?
Diagramme, blöde Nicht-Terminale und Terminale. Ja, okay.
Die Frage ist berechtigt, auch wenn ihr sie
nicht ausgesprochen habt
Und die Dinger sind ganz nützlich, um
die Syntax einer Programmiersprache zu beschreiben. Und eine Programmiersprache,
die ihr ja hier sehr intensiv sehen werdet, ist Java.
Und auch für Java gibt es so eine Syntax-Definition,
die genau auf so einer EBNF-Logik basiert.
Also es gibt Nicht-Terminale und es gibt Herminale und es gibt
diese beliebig oft und so weiter.
Das solltet ihr lesen können. Und für so eine Programmiersprache
wie Java ist es halt nützlich, wenn ihr es lesen könnt.
Also wir können uns das hier mal angucken.
Es gibt tatsächlich hier eine Website,
auf der ist die Sprachspezifikation von Java
frei verfügbar
Also hier jetzt auch die allerneueste Version.
Und ihr seht, das Ding ist ziemlich lang.
Das ist nur der Table of Content und der ist recht lang.
Also hier, da ist schon einiges zu finden. So,
euch sollen nicht schwindelig werden, aber ich rolle mal eben hier runter.
Hier, List of Examples und dann steht hier Syntax.
Ah, die Syntax der Sprache Java.
Gucken wir doch mal drauf, wie die so aussieht.
Aha, Chapter 18, Syntax. The Grammar Below,
uses the falling BNF-Style conventions. Also wir erzählen euch hier nicht
irgendwelchen Blödsinn, sondern etwas, was nützlich ist für Java.
Also hier diese eckigen Klammern, die Nodes Zero or One Accourrences of X
Und dieses geschweifte, die Note Zero or more or Currences of X.
Und X oder Y means Ether One of X or Why.
Dieses Oder tritt hier witzigerweise gar nicht auf,
was die nämlich gemacht haben bei Java, ist,
die haben gesagt, hier steht immer das Nicht-Terminar,
das ist ein Nicht-Terminal mit einem Doppelpunkt.
Und dann stehen die verschiedenen Varianten auf verschiedenen Zeilen.
Und das haben wir halt hergenommen. Also dieses Ding ist
groß. Diese EBNF von Java ist groß und kompliziert.
Also ich kann sie nochmal vielleicht eben Konzert zeigen.
Einmal kurz festhalten jetzt, ja, wir rollen hier mal
runter.
Das ist
ziemlich viel Zeug
So, also, und auch komplex.
Also das ist tatsächlich nicht ganz einfach zu lesen.
Also haben wir gesagt, wir machen es mal anders.
Wir dampfen das mal runter auf eine kleine Syntax für so
ein Subset von Java. Nämlich genau das,
was ihr auf Level 1 hier in SE1 auch zu sehen bekommt.
Und diese Syntaxdefinition, die passt tatsächlich auf eine DIN-A4-Seite. Ja,
die ist also sehr überschaubar, sehr einfach und hält nur die Konzepte,
enthält nur die Konzepte, die ihr bisher kennengelernt habt.
Also eine eigene BNF, die habe ich hier irgendwo auch im Komsi,
wo ist denn das, kommen sie, wo ist denn das,
kommt da, ist das,
kommen sie.
Aha, hier
Also Aufgabenblatt 3. Kommen wir mal drauf, was da so auf euch zukommt.
Hier ist zum Beispiel Java Level 1, die Syntax.
Und die sieht tatsächlich so aus. Tara, sie passt
auf eine Seite. Ich gebe zu, das ist ein
kleiner Font. Da passt viel auf eine Seite,
wenn man den Font nur klein genug macht,
aber das ist tatsächlich deutlich kleiner als die Grammatik von Java.
Aber sie rippusiert das die gleichen Regeln. Das heißt,
dieses Zeug wird auch in den Übungen dann mal so ein bisschen einsetzen.
Hier ist mal so ein Beispiel, ich kenne das glaube
ich hier irgendwo, wo ist denn dieser komische
Da gibt es dann irgendwo diese Lupe.
Leider geht das nicht so, wie das früher mal ging.
Aber man kann hier vielleicht sehen, Statement.
Könnt ihr das lesen oder soll ich das mal größer machen?
So, machen wir es noch ein bisschen größer.
So. Statement. Ja, also ein Statement kann sein.
Ein If-Statement, ein Return-Statement, kann sein eine leere Anweisung,
eine Zuweisung, eine Methodenaufruf oder einen Blog.
So, und dann sind halt diese ganzen Dinger immer wieder
mit nicht-terminalen definiert und dann gibt es für jedes Nicht-Terminal
auch eine Regel
Und das ist tatsächlich etwas, was wir hier extra
für SE1 gebaut haben. Also hier, das Startsymbol,
Compilation Unit, dann dieser rote Doppelpunkt als Ableitungssymbol.
Und dann Terminale im Blau, EBNF-Symbole, diese Meta-Symbole in Rot. So,
und dann sieht man hier so nicht terminal für eine Anweisung hier,
und da gibt es die sechs Alternativen dazu.
So, und dieses, diese Syntaxregeln solltet ihr mal kennenlernen,
wie gesagt, die sind nützlich um Programmiersprachen allgemein zu beschreiben.
Diese Grammatiken werden auch benutzt, um daraus Compiler zu bauen.
Also wenn ihr mal irgendwie mit Compilerboard zu tun haben wollt,
wird das da auch mit behandelt. Ja,
ich habe im Skript jetzt auf den nächsten Folien da so ein Beispiel mal durchdekliniert,
damit ihr nochmal so ein bisschen seht, ja,
wie ist denn das mit diesen Syntaxregeln und was macht denn so ein Compiler?
So ein Compiler, der erzeugt ja nicht aus dem Staatssymbol
irgendwie jetzt wahllos irgendwelche Programme, sondern es ist ja eher anders.
Ihr habt ein Programm geschrieben und der Compiler versucht jetzt zu erkennen,
ob er daraus irgendwie das Staatssymbol wieder zurückableiten kann.
Also andersrum feststellen kann, ob das reduzierbar ist auf das Staatssymbol,
um dann sagen zu können, ja, das ist syntaktisch korrekt, dieses Programm.
Und wenn so ein Programm so ein taktisch korrekt ist,
heißt noch lange nicht, dass es dann auch das tut,
was ihr wollt
Das ist nämlich auch noch so ein Problem.
Syntax ist nur ein Teil der Geschichte.
Das könnt ihr euch nochmal im Skript angucken, dieses Beispiel.
Das ist sozusagen zum Selbstlesen. Das Entscheidende ist,
die Syntaktische Struktur von Programmiersprachen wird häufig in dieser EBNF beschrieben.
Und die Syntax von Java ist in so einer Abwandlung notiert,
die wir euch jetzt ein bisschen näher bringen mit dieser Syntaxdefinition von JavaLevel 1.
Gibt es Fragen jetzt zu diesen Syntaxregeln?
Dann habe ich jetzt noch mal wieder eine Frage an euch.
So, jetzt mal wieder eine kleine Umfrage. Mal sehen,
was ihr bis jetzt verstanden habt von dem,
was ich erzählt habe. Nehmen wir mal an,
wir haben diese
sehr einfache Syntaxdefinition
Ja. Das soll EBNF sein. Und Ausdruck ist das Staatssymbol.
Ihr seht also zwei Nicht-Terminale und auch nur zwei Regeln.
Wobei bei dem einen Nicht-Terminal sind es ja drei Alternativen.
So, jetzt kommt hier wieder mein beliebtes Sturesi ins Spiel.
Wie viele verschiedene Ausdrücke, formal Wörter, definiert diese Grammatik.
Also sind es drei, sechs,
acht oder neun
Also wir haben bei der anderen Grammatik eben gesehen,
dass beliebig viele Ausdrücke generiert werden konnten.
Wie viele verschiedene Wörter könnt ihr mit dieser Grammatik hier bauen?
A, B, C oder D. Die Abstimmung ist gestartet
. Ihr könnt jetzt eure Stimmen abgeben. Versucht mal,
das jetzt durchzudenken, wie man da die Nicht-Terminale ersetzen kann
Okay, wir haben wieder 200 Stimmen, sehr schön.
Ich stoppe das mal. Wir schauen mal auf das Ergebnis
. Aha. Also, 55 Prozent sind der Meinung,
es sind neun verschiedene Wörter, die hier erzeugt werden können.
Also neun verschiedene Ausdrücke. Und dann gibt es
auch andere Meinungen, aber das ist ein gutes Ergebnis.
Weil es ist tatsächlich auch das richtige Ergebnis.
Wie kommt das? Naja, wir können natürlich hier
den Bezeichner durch A, B oder C setzen.
Und den Bezeichner hier können wir auch durch A, B oder C setzen.
Das heißt also, es ist drei, mal drei Möglichkeiten,
das zu kombinieren. Man kann also A, A,
B, A, C und so weiter kombinieren.
Da ist eine Frage dazu. Das ist auf jeden Fall
was unterschiedliches. Ja, es ist ja syntaktisch unterschiedlich,
ob es eine andere Bedeutung hat, ist was anderes.
Das ist eine gute Frage. Der hat gefragt,
ist A plus B was anderes als B plus A?
Das ist eine super Frage, weil tatsächlich die Semantik dessen,
was da steht, das ist wieder eine andere Frage.
Aber syntaktisch ist auf alle Fälle A plus B was anderes als B plus A.
Es gibt Sprachen, da ist die Reihenfolge,
in der was steht, auch wichtig für die Auswertung.
Also es kann total auch semantischen Unterschied machen.
Syntaktisch ist es auf jeden Fall ein Unterschied. Okay,
ich habe noch eine. Einen habe ich noch. Ich
habe diese Syntagsdefinition in EBNF. Ja, ich hoffe,
ihr wisst noch, was diese eckige Klammer bedeutet.
Gut, meine Frage ist, wie viele verschiedene Zuweisungen definiert diese Grammatik.
Ich dachte, die Abstimmung und ihr könnt eure Stimme abgeben.
Ja, also das soll jetzt ein bisschen andeuten wie eine Zuweisung aussehen kann.
Man kann da irgendwie anscheinend einen Plus dabei haben oder
auch nicht
Okay, sind ja ziemlich viele Stimmen dabei jetzt hier.
Das ist ja wunderbar. Ich beende das,
weil die Zeit ist auch gleich rum.
Wir gucken uns das Ergebnis an. Acht. 70 Prozent
sagen acht. Und das ist auch richtig, genau.
Weil ich natürlich A, B, A, A,
ich habe also vier Möglichkeiten, A und B zu kombinieren.
Und dazwischen kann entweder stehen ein Gleichheitszeichen oder ein Plusgleich.
Also zwei Möglichkeiten jeweils. Also zweimal vier sind acht.
Und damit habt ihr schon mal die Grundideen von diesen Syntagsregeln
verstanden. Und wenn ich noch Fragen sind,
dann sind wir fertig für heute.
Vielen Dank