Dann darf ich Sie zum achten Termin im Vorkurs begrüßen.
Wir haben ja gestern uns angeschaut, wie man Klassen mit Methoden
versieht und die einsetzt, um die Eigenschaften der Objekte zu
verändern oder bestimmte Aufgaben zu erfüllen.
Und heute gucken wir uns etwas genauer an, wie die Modifikatoren,
insbesondere der Unterschied zwischen statisch und nicht-statisch und
die verschiedenen Sichtbarkeitsbereiche und die verschiedenen
Variabentypen da zusammenspielen, wenn Sie Objekte einsetzen und
benutzen, um Aufgaben zu lösen.
Zunächst einmal in der objektorientierten Programmierung.
Die kriegen Sie jetzt sozusagen in Rohformat von mir für die
Programmiersprache Java, aber später im Studium müssen Sie das in
einem Kontext sehen.
Objektorientierte Programmierung ist gemacht worden, um komplexere
Programme zu verwalten, austauschbar und wartbar zu machen.
Später auch, um grafische Interaktionen mit dem Benutzer praktisch
realisieren zu können, auch auf Programmierebene.
Und heute in den modernen Betriebssystemen und bei den meisten höheren
Programmiersprachen sind objektorientierte Konstrukte nicht mehr
wegdenkbar.
Allerdings ist OOP nicht effizient.
Das heißt, wenn Sie später effiziente Algorithmen programmieren
wollen, müssen Sie teilweise objektorientierte Programmierung auch
gezielt umgehen können.
Ein typisches Beispiel, was ich da immer bringe, sind die DDB
-Automaten, die Sie an den Bahnhöfen finden.
Die bieten Ihnen ein mit OOP programmiertes benutzerfreundliches
Interface, um Ihre Zugverbindung auszuwählen, aber dahinter hängt eine
Datenbank, die nicht objektorientiert programmiert ist und die auf
effiziente Weise aus Millionen von Einträgen für Sie die günstigste
Verbindung sucht.
Diese Kombination hinzubekommen, das ist so ein bisschen die
Schwierigkeit, die ein Informatiker später lösen muss.
Das OOP selbst wird dann später nur ein Mechanismus sein, den Sie eben
beherrschen müssen.
Ich stelle mal kurz vor, wie diese verschiedenen Ansätze in der
objektorientierten Programmierung gelöst sind.
Das macht jede Programmiersprache ein bisschen anders.
Ich habe es mal ein bisschen nach Extremen sortiert.
Das eine Extrem sind reine objektorientierte Sprachen wie Smalltalk,
die auch gar keine elementaren Typen wie Integer oder Byte mehr
kennen.
Die sind natürlich dann sehr ineffizient und eher für Planungsarbeiten
oder für Designkonzepte gedacht.
Dann am anderen Ende gibt es hardwareorientierte Sprachen wie C oder
C++, die eine strenge Typisierung, Templates, Zeiger und Hardwarenähe
haben und auf die die Objektorientierung so eine Art Aufsatz ist, der
auch ursprünglich nicht mit dabei war, sondern der später dazugekommen
ist beim Übergang von C zu C++.
Die Programmiersprache Java ist also ein Mittelweg.
Das heißt, man hat versucht, eine pragmatische Objektorientierung zu
realisieren.
Sie haben Referenzen statt Zeiger.
Den Unterschied habe ich Ihnen ja gestern erklärt.
Sie haben immer noch strenge Typisierung und die Syntax von C++,
allerdings ein bisschen vereinfacht.
Aber Sie haben auch die Möglichkeit, wenn Sie das möchten, die
Objektorientierung zu umgehen und nur mit elementaren Datentypen und
Feldern zu arbeiten.
Das schauen wir uns heute auch so ein bisschen an.
Dann modernere Sprachen wie JavaScript zum Beispiel beherrschen ein
sogenanntes prototypisches objektorientiertes Programmieren.
Das heißt, Sie haben keine richtigen Klassendefinitionen mehr.
Dann gibt es in den moderneren Sprachen wie Python oder JavaScript das
sogenannte Ducktyping.
Das heißt, es werden zwar schon Typen von Variablen unterschieden,
aber der Typ muss nicht mehr vorher festgelegt werden.
Und Sie haben keine echten Klassen mehr.
Das heißt, Sie können so etwas machen wie eine Lehrerklasse anzulegen
und während der Laufzeit des Programms dieser Klasse Methoden oder
Variablen zuzufügen.
In Java ist das alles nicht erlaubt.
Da ist es etwas systematischer und strukturierter.
In klassischen Sprachen wie Pascal oder Delphi, haben ja einige
vielleicht schon gesehen, haben sie ursprünglich einen prozeduralen
Ansatz gehabt, der später durch objektorientierte Elemente erweitert
wurde.
Und das sieht man diesen Sprachen auch heute noch an, dass die
objektorientierten Elemente da irgendwie künstlich draufgesetzt
wurden.
Java ist ein Mittelweg aus allen diesen Ansätzen und letztlich können
Sie, wenn Sie wollen, in Java alles objektorientiert programmieren und
an den Stellen, wo Effizienz gefordert ist, auf die elementaren
Datentypen umsteigen und nachher mit Hilfe des Static-Modifikators die
Objektorientierung mehr oder weniger ausschalten.
Heute gucken wir uns zunächst einmal die ganzen Konzepte für Variablen
etwas genauer an.
Wir schauen uns an, aus welchen Vorlagen Variablen erzeugt werden und
in welchem Kontext, in welchen Situationen, welchen Lebenslauf sie
haben, wo sie im Speicher abgelegt werden und wo sie in ihrem
Programmcode tatsächlich sichtbar, zugreifbar und verwendbar sind.
Und das Gleiche dann auch nochmal für die Methoden.
Zur kurzen Wiederholung.
Java kennt elementare Datentypen, die acht Stück, die Sie auswendig
kennen sollten.
Felddatentypen, halt irgendein bekannter Datentyp und die eckigen
Klammern dahinter, um klar zu machen, dass Sie eine Feldreferenz auf
die entsprechenden Typen meinen.
Klassen sind die einzigen Typen, die Sie selber in einer Java-Datei
separat deklarieren müssen, bevor Sie sie überhaupt verwenden können.
Sie müssen Java sozusagen erklären, was in einem Objekt dieser Klasse
drin ist.
Sobald Sie das getan haben, können Sie die Variablen anlegen und da
haben wir gelernt, dass bei elementaren Typen die Variable mit ihrer
Speicherzelle mehr oder weniger identisch ist, aber bei Feldern und
Klassen müssen Sie unterscheiden zwischen der Referenz, die das Objekt
kontrolliert, und dem tatsächlichen Bereich im Speicher, auf den Sie
in der Regel gar keinen Zugriff haben.
Die Klasse ist die Vorlage, die ist sozusagen der Datentyp für die
Objekte und sie legt fest, welche Attribute und welche Methoden in der
Klasse enthalten sind und mit dem New Operator können Sie dann
Instanzen oder Objekte dieser Klasse erzeugen und sobald Sie die
haben, manipulieren.
Manipulieren heißt im Moment, dass Sie mit dem Referenzpunkt auf
Attribute zugreifen können oder auf Methoden und Sie haben es gestern
schon im Style Guide gesehen, eigentlich zwingen wir Sie ja, solche
Zugriffe hier u.x.
grundsätzlich zu verbieten, indem Sie die Variablen auf private setzen
und nur noch get und set Methoden benutzen, um die Variablen zu
manipulieren.
Da sage ich auch heute noch ein bisschen mehr dazu.
Das allererste, was wir uns da angucken müssen, ist der Modifikator
Static.
Den haben wir gestern und vorgestern so ein bisschen ausgeblendet.
Ich habe aber schon gesehen, dass einige von Ihnen den benutzt haben.
Und der Unterschied zwischen statisch und nicht statisch besteht
letztlich darin, dass in Java alles, was nicht statisch ist, an ein
Objekt gebunden ist.
Das heißt, das Objekt muss konkret im Speicher sein.
Ich habe das hier an der Tafel immer so visualisiert, dass es da
diesen Kasten im Speicher gibt und die Attribute sind eben in diesem
Kasten drin.
Das ist natürlich nur eine Visualisierung.
In Wirklichkeit sagt man, diese Datenwerte oder die Methoden sind an
das Objekt gebunden.
Man kann sie von diesem Objekt aus aufrufen, wo die dann konkret im
Speicher sind.
Das ist ja gar nicht unter Ihrer Kontrolle.
Wir stellen uns das so vor, dass jedes Objekt seine Attribute und
Methoden in seinem eigenen Speicherbereich hat, auch wenn der Compiler
das intern natürlich optimieren wird.
Und jedes Mal, wenn Sie einen new Befehl ausführen und ein neues
Objekt, einen neuen Raumvektor oder sonst über eine Klasse definiertes
Objekt erzeugen, werden diese Attribute und Methoden neu in den
Speicher geschrieben und separat für dieses Objekt verwaltet.
Auch das ist in der Wirklichkeit streng genommen nicht so.
Wenn 200 Objekte die gleiche Methode haben, dann wird der Compiler die
natürlich nicht 200 Mal in den Speicher schreiben, sondern nur ihnen
gegenüber so tun, als ob das so wäre.
Wenn Sie dagegen den Modifikator static davor schreiben, dann heben
Sie diese Objektbindung auf.
Attribute und Methoden, die statisch sind, kriegen dieses
Schlüsselwort static vor die Deklaration und sind damit nicht mehr an
das Objekt gebunden, sondern sie existieren sofort nach dem Start des
Programms.
Sie existieren unabhängig davon, ob und wie viele Objekte es von dem
Typ gibt.
Und sie stehen auch nicht in dem Speicherbereich des Objekts, sondern
in einem globalen, für statische Elemente reservierten Bereich.
Statische Attribute und Methoden gibt es nur einmal.
Und alle Objekte, die zu der Klasse gehören, teilen sich, diese
einzelne Variable oder diese einzelne Methode.
Die Sprechweise, die man bei Java da hat, ist, dass man sagt,
gewöhnliche Attribute und Methoden sind an das Objekt gebunden,
statische Attribute und Methoden sind dagegen an die Klasse gebunden.
Und die Klasse gibt es nur einmal, ganz egal, wie viele Objekte sie
erzeugen.
Das versuche ich Ihnen mal ein bisschen zu veranschaulichen.
Wenn Sie den gewöhnlichen Raumvektor haben, also das Raumvektor XXYYZ,
und Sie erzeugen mit New zwei Stück, wie eben im Beispiel, dann haben
Sie zwei Objekte im Speicher und jedes Objekt hat sein eigenes X, sein
eigenes Y, sein eigenes Z.
X alleine gibt es nicht, es gibt nur U.X und es gibt V.X und das sind
zwei verschiedene Variablen.
Das ist die nicht-statische Situation.
Hier sind die einzelnen Attribute an ihr Objekt gebunden.
Im Programm selbst sieht das halt so aus, dass Sie die Raumvektoren
erzeugen, Raumvektor V gleich New Raumvektor, dann können Sie auf V.X
zugreifen oder hier W.X ausgeben und wenn Sie einfach nur so X
hinschreiben, dann kriegen Sie eine Fehlermeldung, weil Java sagt, X
kenne ich nicht, ich kenne nur V.X und W.X.
Das ist die objektgebundene Situation, so haben wir es bisher immer
gemacht.
Wenn Sie jetzt Static da vorschreiben, und ich mache das mal, das
macht für einen Raumvektor nicht wirklich Sinn, aber nur, dass Sie den
Unterschied sehen.
Ich setze jetzt die Variable X auf Statisch mit diesem Modifikator,
dann ist sie nicht mehr objektgebunden.
Das heißt, sie ist nicht mehr in den einzelnen Objekten enthalten,
sondern es gibt in einem speziellen Speicherbereich nur noch ein
einziges X, das für alle Raumvektoren geteilt wird.
Habe ich mal hier oben in die Ecke geschrieben.
Und in den einzelnen Objekten selbst gibt es nur noch Y und Z.
Jetzt gibt es U.Y und V.Y und es gibt auch U.X und V.X, aber U.X und V
.X sind jetzt das gleiche, nämlich das gelbe hier oben und im Grunde
könnte man das Objekt U oder V davor auch weglassen und einfach sagen,
das ist das X, das zu allen Raumvektoren gehört.
Das Bild sollten Sie sich einprägen, das beschreibt sehr schön, was
der Modifikator Static tut.
Warum möchte man das denn haben?
Warum möchten Sie eine einzelne Variable aus einem Objekt herauslösen
und zwischen allen Objekten teilen?
Gibt es Situationen, wo Sie so etwas tun möchten?
Bei Konstanten zum Beispiel, da macht es nur Sinn, wenn die einmal da
sind.
Können Sie sich auch vorstellen, dass man sowas für Sachen haben
möchte, die nicht konstant sind?
Irgendeine Anwendung, wo eine Variable von allen Objekten geteilt
wird.
Macht sowas überhaupt Sinn?
Das macht sehr viel Sinn, zum Beispiel, wenn die Objekte irgendwie
untereinander kommunizieren sollen.
Dann brauchen Sie irgendwie etwas Gemeinsames, wo Sie Daten ablegen
können.
Oder wenn Sie einfach zählen möchten, wie viele Raumvektoren überhaupt
erzeugt worden sind.
Dann brauchen Sie eine Variable, Zähler, die in jedem Objekt
hochgezählt wird, in einem Konstruktor, wenn es erzeugt wird.
Aber das muss dann überall die gleiche Variable sein, sonst hat jedes
Objekt einfach nur den Zähler gleich eins.
Verstehen Sie das?
Dass dieser Bedarf einfach da ist.
Und der zweite Bedarf ist, das was ich vorhin angedeutet habe, wenn
Sie aus Effizienzgründen die Objektorientierung aushebeln möchten,
dann können Sie das mit dem Modifikator Static tun.
Wenn Sie ein Feld haben mit 10 Millionen Einträgen, das irgendwie
bearbeitet werden soll, und Sie möchten nicht, dass das über so eine
Referenz im Speicher hängt, dann sollten Sie es auf Static setzen.
Das macht es wesentlich effizienter.
Aber dann gibt es das halt auch nur einmal.
Und Sie müssen darauf achten, dass die Objekte, die darin
rumschreiben, sich nicht gegenseitig stören.
In der Anwendung sieht das dann so aus.
Also hier habe ich jetzt oben wieder die Klassendefinition.
Class Raumvektor mit Static Double X.
Und im Programm selbst könnte man jetzt v.x gleich minus 1 setzen.
Und dann w.x mit print ausgeben und bekommt dann diese minus 1, weil
es das x jetzt nur einmal gibt.
Und diesen Effekt, den muss man immer beachten, wenn man irgendetwas
auf Statisch setzt.
Tatsächlich brauchen Sie gar kein Objekt, Sie müssen gar keinen
Raumvektor erzeugen.
Sie können einfach schreiben Raumvektor, das ist der Name der Klasse,
nicht der Name eines konkreten Objekts, Raumvektor.x gleich minus 2.
Es muss überhaupt kein Objekt im Speicher sein.
Die Variable lebt sozusagen von Anfang an und ist da.
Warum muss ich denn da trotzdem noch diesen Raumvektor davor
schreiben?
Warum kann ich jetzt nicht einfach sagen x gleich minus 2, es gibt
doch nur 1, oder?
Genau.
Jetzt müssen Sie aufpassen, es ist immer noch gebunden.
Es ist zwar nicht mehr an die Objekte gebunden, aber es ist an die
Klasse gebunden.
Und eine andere Klasse könnte auch ein x statisch haben.
Das heißt, Sie müssen immer noch nach Klassen trennen.
Raumvektor.x Das ist ein wichtiger Unterschied zu anderen
Programmiersprachen.
Sie haben in Java grundsätzlich keine Möglichkeit, so etwas wie
globale Variablen zu deklarieren.
Sie können zwar in Ihrer public static void main oder darüber ein
static x anlegen, aber das ist dann eigentlich nicht global, sondern
wo liegt das?
Genau, das gehört dann zu dieser Klasse meinProgramm.
Sie haben überhaupt keine Möglichkeit, das außerhalb von einer Klasse
zu deklarieren.
Zu irgendeiner wird es gehören.
Das ist jetzt wegen Java.
Es darf keine herrenlosen Variablen sozusagen geben.
Gut, das geht nicht nur für Variablen, sondern es geht auch für
Methoden.
Also wenn Sie jetzt so einen Raumvektor haben, dem gebe ich jetzt mal
eine Printmethode.
Eigentlich dürfen Sie das als Informatiker nicht, Objekte sollen nicht
direkt auf die Konsole schreiben.
Und Sie müssen das als toString machen.
Aber ich mache es jetzt trotzdem mal, weil es bei diesem Beispiel so
gut passt.
Sie haben also eine Printmethode, die den Vektor ausgibt.
Und die greift einfach auf x, y und z zu.
Und wenn das Objekt gebunden ist, weil nicht statisch davor steht,
dann ist auch, wenn Sie nicht diesen Modifikator this benutzen, für
Java an der Stelle klar, dass Sie dieses x, dieses y und dieses z
meinen und keine anderen.
Deshalb funktioniert das hier unten auch so schön.
Und das x, y und z von dem v sind eben andere als das x, y und z von
dem w.
Wenn Sie jetzt die Methode auf statisch setzen, dann gibt es diese
Methode nur einmal und sie ist außerhalb von dem Objekt.
Jetzt wird Ihnen Eclipse Fehler anzeigen und sagen, Entschuldigung,
ich kenne kein x.
Ich bin nicht in diesen Kästen drin.
Ich habe keine Ahnung, was x ist.
Das Problem können Sie prinzipiell beheben.
Und das ist eigentlich auch gar keine so schlechte Lösung, aus
Effizienzgründen, wenn Sie der statischen Methode beim Aufruf Ihr
Objekt mitgeben.
Das klingt jetzt ein bisschen komisch, aber ich zeige Ihnen mal, wie
das aussieht.
Sie würden sozusagen static void print schreiben.
Das ist nur eine einzige Printmethode, die ist zuständig für alle
Raumvektoren.
Und Sie müssen der Methode dann mitgeben, welchen Raumvektor sie
ausgeben soll.
Und dann kann sie von außen auf die Attribute von u zugreifen und
diese ausgeben.
Das tut semantisch und syntaktisch das gleiche wie die objektgebundene
gewöhnliche Printmethode, die ich Ihnen vorhin gezeigt habe.
Aus Effizienzgründen wäre das hier eigentlich besser als das, was Sie
vorher hätten.
Warum?
Auch wenn Sie die gleiche Ausgabe kriegen.
Warum ist das hier effizienter, als jedem Objekt seine eigene
Printmethode mitzugeben?
Ja, also das tut zwar genau das gleiche wie die objektgebundene
Methode eben, aber in diesem Fall gibt es eine Printmethode im
Speicher, die verschiedene Vektoren ausgeben kann.
In dem anderen Fall, diesem hier, hat jeder Raumvektor seine eigene
Printmethode.
In jedem Speicherbereich ist die Printmethode drin.
Das ist zwar überall die gleiche, aber sie ist in jedem
Speicherbereich drin.
Und das ist Verschwendung.
In Wirklichkeit ist es natürlich nicht so, der Compiler sieht, dass
das Verschwendung ist und wird sie nur in einen Kasten reinschreiben
und in die anderen dann Verweise setzen.
Das sehen Sie als Programmierer nur nicht.
Aber das da ist sozusagen rein von der Effizienzkalkulation her das
Effizienteste.
Die Methode ist nur einmal im Speicher und sie bekommt nur jedes Mal
andere Datenwerte.
Das verbieten wir Ihnen aber.
Warum?
Bezieht sich jetzt nur auf die Studiengänge Informatik und
Informationswirtschaft.
Das liegt einfach daran, dass wir Ihnen etwas anderes verboten haben,
was Sie dafür brauchen.
Sie müssen von außen auf die Attribute zugreifen und das dürfen Sie
nicht.
Sie können natürlich, wenn Sie ordentliche Get- und Set-Methoden
geschrieben haben, jetzt hier jedes Mal die Get-Methode für diese drei
Variablen aufrufen, aber dann haben Sie Ihre Effizienzgrad wieder
verloren.
Deshalb machen wir das grundsätzlich nicht so.
Später, wenn Sie effizient programmieren müssen, wenn Sie eine
Billiarde Datenwerte haben, die Sie durchgehen und irgendwo verwalten
müssen, dann ist das hier die effizienteste Form, das zu tun.
Aber das würden Sie dann sowieso nicht mehr in Java machen.
Gut.
Ich fasse Ihnen mal kurz zusammen, was ich Ihnen da gerade vorgestellt
habe.
Methoden und Variablen können objektgebunden sein, indem Sie einfach
nicht static davor schreiben, dann verändern oder gehören die
irgendwie zu den Eigenschaften des Objekts, geben den Inhalt des
Objekts nach außen weiter und realisieren irgendwie den Zweck des
Objekts.
Das ist so die Idee, die man dahinter haben sollte.
Und Sie dürfen auf die Attribute des eigenen Objekts entweder mit dem
Referenzpunkt oder mit Vis von innen zugreifen.
Statische Methoden dagegen sind nicht mit dem Inhalt oder Zweck des
Objekts verbunden.
Die bekommen ein Objekt gegebenenfalls als Parameter und greifen auf
die Attribute bzw.
die Methoden mit dem Referenzpunkt zu, und zwar von außen.
Das ist der wichtige Unterschied.
Ich gebe Ihnen ein paar Beispiele.
Wenn Sie die Klasse String haben, benutzen Sie ja ständig, dann haben
Sie da zwei Methoden, zum Beispiel charAt gibt Ihnen das Karte
-Schriftzeichen, das in Ihrem String drin ist, oder equals vergleicht
Ihren String mit einem anderen String.
Beide Methoden hängen von dem Inhalt Ihres konkreten Strings, den Sie
haben, ab.
Deshalb sind die objektgebunden und nicht statisch in dieser
Deklaration.
Das sind typische objektgebundene Methoden, die benutzen irgendwie die
Eigenschaften Ihres Objekts und können ohne die auch gar nicht
funktionieren.
Das da unten sind zwei Beispiele für statische Methoden oder statische
Attribute, zum Beispiel den Sinus oder auch den Mittelwert, den Sie
gestern programmiert haben.
Da ist überhaupt kein Objekt beteiligt.
Der Sinus ist eine Funktion, da geben Sie eine reelle Zahl rein und
kriegen eine reelle Zahl raus und alles andere hat damit nichts zu
tun.
Das ist statisch, oder müssen Sie auf statisch setzen, sonst macht es
irgendwie keinen Sinn.
Konstanten genauso, wie eben richtig gesagt wurde.
Erstmal wollen Sie ja da, dass überall die gleiche Konstante ist.
Das ist sozusagen der Sinn von einer Konstante.
Und es ist eine unveränderliche Zahl, können Sie noch Final davor
schreiben.
Und es reicht, wenn sie einmal im Speicher ist.
Und sie ist nicht an ein Objekt gebunden.
Sie müssen Math.py benutzen können, egal ob Sie schon Math-Objekte
überhaupt erzeugt haben oder nicht.
Auch da gibt es ein bisschen Style Guide, wenn Sie etwas haben, was
eine Konstante ist.
Also was sowohl den Modifikator Static wie den Modifikator Final hat.
Dann schreiben Sie das durchgehend mit Großbuchstaben.
Groß P, Groß I.
Damit jemand, der den Code liest, versteht, dass das etwas ist, was
überall gleich ist und was nicht verändert werden darf.
Werde ich jetzt auch auf den Folien immer so durchziehen.
Haben Sie zu diesen beiden Konzepten, objektgebunden, individuell,
statisch und für alle gleich, Fragen.
Das ist etwas, das lernt man eigentlich erst so beim Programmieren,
wenn man die Aufgaben hat, wie sich das konkret auswirkt.
Wir üben das jetzt mal an einer etwas längeren Aufgabe.
Sie schreiben auf ein Blatt Papier eine Klasse Math, die einen
bewegten Massekörper in der Physik darstellen soll.
Ich habe Ihnen sechs Eigenschaften eines solchen Körpers aufgelistet.
Aus Sicht der Physik, nicht aus Sicht der Informatik.
Und Sie müssen jetzt aus Sicht der Informatik, aus Sicht von Java und
Ihrem Styleguide, entscheiden, wie Sie diese Eigenschaften
realisieren.
Sie müssen jeweils wählen, ist das überhaupt eine Variable oder ist
das eine Methode?
Ist das Public oder nicht?
Ist das Static oder nicht?
Ist das Final oder nicht?
Da gibt es auch nicht eine richtige Lösung, sondern wir werden mehrere
Lösungen diskutieren.
Aber ich gebe Ihnen jetzt erstmal zehn Minuten Zeit, das auf ein Blatt
Papier zu füllen.
Schreiben Sie keinen Rumpfcode.
Sie müssen jetzt insbesondere da unten bei den beiden Methoden keine
Befehle reinschreiben.
Schreiben Sie nur die Signaturen, nur die erste Zeile.
Es geht nur darum, wie man es richtig deklariert.
Es geht nicht darum, wie man es konkret mit Befehlen füllt.
So, ich würde vorschlagen, wir fangen mal an zu diskutieren.
Zögern Sie nicht, mir jetzt Signaturen oder Attribute vorzuschlagen.
Ich mache den Vorkurs seit fünf Jahren, ich habe bisher noch nie auf
Anhieb eine richtige Antwort gekriegt.
Das ist bei dieser Aufgabe so.
Sie müssen auch keine Angst haben, es wird aus der Aufzeichnung
herausgeschnitten.
Also scheuen Sie sich nicht und schlagen Sie mir etwas vor.
Die Probleme sind hier nämlich nicht nur informationstechnischer
Natur, sondern auch physikalischer Natur.
Ja, als Private Doubles.
Wie würden Sie die Masse und die Geschwindigkeit denn benennen?
m und v.
Alle einverstanden?
Kann man jetzt streiten, ob das aussagekräftige Variablen sind?
Wenn Sie den Hintergrund haben, dass das bekannte Symbole aus der
Physik sind, würde ich sagen ja.
Und da haben Sie jetzt Glück, dass das in der Physik ein kleines m und
ein kleines v ist, sonst hätten Sie einen Style-Guide-Konflikt.
Okay, damit bin ich auch einverstanden.
Das war der einfache Teil.
Was machen wir mit der kinetischen Energie?
Wissen Sie alle, was kinetische Energie ist?
Haben Sie das im Physikunterricht gehabt an der Schule?
Okay, ich muss die Frage anders stellen.
Hatten Sie Physikunterricht an der Schule?
Ja.
Gut, bis zur Klasse 12.
Da fangen dann einige an, den Kopf zu schütteln.
Okay, auch wenn Sie nicht wissen, was es ist, da unten steht ja so
eine hübsche Formel, was mache ich denn mit der?
Genau.
Da reden wir aber jetzt über zwei verschiedene Lösungen und die
trennen wir mal.
Also Sie schlagen vor, das in eine Methode zu packen.
Diktieren Sie mir mal eine Signatur.
Okay, also bei dem können Sie mir den Programmcode schon dazugeben.
Es steht ja faktisch da.
Punkt 0 durch...
Oder so, genau.
Das wäre auch eine Möglichkeit, nur 1 durch 2 dürfen Sie halt nicht
machen.
Mal V, genau, weil Java keine Quadrate kann.
Okay, ich tue es mal in die nächste Zeile, dass man alles sieht.
So, sind alle damit einverstanden?
Das ist erstmal aus Sicht der Informatik, aus Sicht von Java, eine
gültige Methode mit richtigen Modifikatoren.
Und die Formel funktioniert auch genauso, wie Sie es erwarten.
Ist das auch aus Sicht der Physik richtig?
Ist das so, dass wenn M und V sich ändern, dass die kinetische Energie
automatisch auch sich ändert?
Das ist eine Physikfrage.
Ja, das ist so.
Genau genommen haben Sie in der Physik hoffentlich gelernt, dass es
einen funktionalen Zusammenhang zwischen diesen drei Objekten gibt.
Und deshalb ist das die erste richtige Möglichkeit, das auszudrücken.
Die zweite Möglichkeit.
Gibt es eine zweite Möglichkeit, das zu machen?
Die zweite Möglichkeit wäre das hier gewesen.
Wenn ich es auch private mache.
Sorry, das ist eine neue Tastatur.
private double e Das wäre erstmal nicht richtig.
Aber, wie könnte man es denn richtig machen?
Wenn ich unbedingt möchte, dass das eine Variable ist.
Und dann können wir diskutieren, warum das sogar sinnvoll sein kann.
Ja?
Wann müssen Sie die neu berechnen?
Genau.
Das haben wir nämlich hier oben irgendwie vergessen.
Wenn wir die auf private setzen, dann brauchen die get und set
-Methoden.
Und wenn man die get und set-Methoden, also z.B.
ZM, double M, wenn man die jetzt richtig schreibt, und so anpasst,
dass eben nicht nur, und das ist ja der Sinn von so einer set-Methode,
dass nicht nur this.m auf M gesetzt wird, sondern dass auch dieses e
angepasst wird.
Und zwar wieder mit der gleichen Formel.
Dann funktioniert das auch, ohne dass man die kinetische Energie als
Methode macht.
Und jetzt hätte ich eine nicht ganz einfache Frage an Sie.
Welche von den beiden Lösungen ist denn effizienter?
Da gibt es keine einfache Antwort drauf.
Da müssen Sie einen Moment überlegen.
Ja?
Es kommt drauf an, wie man die Klassik verwendet.
Genau.
Das ist ein ganz wichtiger Typ von Antwort, den Sie lernen müssen.
Es kommt drauf an.
Das kommt drauf an, ob Sie in Ihren Objekten später bei der konkreten
Aufgabe, die Sie lösen, sehr sehr oft nach der Energie fragen, oder
sehr sehr oft die Masse ändern, oder die Geschwindigkeit ändern.
Je nachdem ist die eine Lösung besser oder die andere.
Pauschal können Sie das gar nicht entscheiden.
Und ich nehme jetzt die Lösung mit der Methode.
Nur deshalb, weil es auch meine Musterlösung ist.
Aber es gibt sozusagen aus philosophischer Sicht jetzt keinen Grund,
warum das besser sein soll.
Und den Zetter für das M tue ich auch mal dazu.
Und der braucht sozusagen das hier jetzt nicht mehr.
Den Zetter haben wir vorhin ganz vergessen.
Ist der überhaupt richtig so?
Nach allem, was Sie hier gelernt haben.
Auch das ist keine einfache Frage.
Ja?
Genau.
Je nachdem, wie streng Ihr Physiklehrer das gehandhabt hat, müssen Sie
hier jetzt eigentlich prüfen, ob das ein sinnvolles M ist.
Da würde ich sogar so weit gehen und sagen, M gleich 0 ist auch nicht
erlaubt.
Also wenn M kleiner gleich 0, dann müssen Sie halt irgendwas anders
machen, oder halt mit einem Printbefehl meckern.
Kann man jetzt streiten, ob es im Universum Objekte mit der Masse 0
gibt.
Die Quantenphysik sagt nein.
Die Relativitätstheorie sagt ja.
Aber das liegt halt daran, dass die Physik keine exakte Wissenschaft
ist.
Aus Sicht von Mathematikern und Informatikern.
Das sehen die Physiker natürlich anders.
Gut.
Aber das ist sozusagen jetzt kein Java-Problem, sondern das liegt halt
daran, was Sie da eigentlich an Problemstellungen letztlich lösen
wollen.
Gut.
Double private, double V für die Geschwindigkeit.
Da könnte ein engagierter Physiklehrer auch meckern.
Ist das der richtige Datentyp für die Geschwindigkeit?
In einigen Bundesländern wird es im Leistungskurs Physik noch gemacht.
In Baden-Württemberg glaube ich nicht.
Eigentlich ist die Geschwindigkeit eine vektorielle Größe.
Genau.
Eigentlich ist die Geschwindigkeit eine vektorielle Größe.
Welchen Datentyp würden Sie dem geben?
Sie haben schon einen.
Nehme ich den Raumvektor.
Das wäre eigentlich richtig.
Also wenn wir in einem dreidimensionalen Universum leben, wo ich auch
gehört habe, dass das nicht stimmt.
Aber es ist das Beste, was wir jetzt haben.
Damit der Programmcode, den wir jetzt schreiben, nicht so entsetzlich
kompliziert wird, mache ich es trotzdem so.
Okay?
Und dann ist es halt ein Massepunkt auf einer Geraden.
Und sonst nichts.
Gut.
Das war die Geschwindigkeit und die kinetische Energie.
Was ist denn mit der Fallbeschleunigung?
Was machen wir mit der?
Static double.
Und dann halt die 9.81.
Zwei Sachen stören mich.
Aber das sind auch Sachen, wo man diskutieren kann.
Okay.
Sie sagen, die kann nicht verändert werden.
Ist das so?
Ja.
Also hier auf der Erde schon.
Wobei Sie da gar nicht die Frage stellen müssen, ob die Erde jetzt
ihre Fallbeschleunigung ändern können muss oder nicht.
Sondern das liegt halt daran, ob Ihr Programm in der Lage sein muss,
mit Änderungen klarzukommen oder nicht.
Ich würde das so unterstützen mit Final.
Static double G.
Aber im Grunde ist das auch jetzt keine Informatik, sondern eine
Physik -Fragestellung.
Kleines G oder großes G?
Auch die Frage lässt sich nicht so einfach beantworten.
Beim Final müsste es sehr groß werden.
Genau.
Unser Style-Guide erzwingt eigentlich das hier.
Aber jetzt gibt es noch einen anderen Style-Guide, nämlich die Physik,
die erzwingt eigentlich das da.
Das große G gibt es in der Physik auch, das ist aber was völlig
anderes.
Jetzt haben Sie einen Style-Guide-Konflikt.
Wie lösen Sie den denn?
Den lösen Sie jetzt nicht mit Regeln, sondern mit gesundem
Menschenverstand.
Ich schreibe einfach Fallbeschleunigung unter Strich Erde.
Jawohl.
Das ist die sinnvolle Lösung.
Und wenn Sie clever sind, schreiben Sie auch noch Fallbeschleunigung
unter Strich Erde.
Das ist die richtige Lösung.
Das steht in keinem Style-Guide.
Auf die Idee müssen Sie jetzt selber kommen.
Dass das die beste Lösung ist, diesen Konflikt zu umgehen.
Fragen dazu?
Ja.
Sollten Sie auch.
Unbedingt.
Ich mache mal einen dazu.
Ich mache es jetzt nicht immer, weil die Folie so voll wird.
Aber später, wenn Sie in Ihrer Programmieren-Vorlesung sind, werden
wir Sie sowieso zwingen, alles und jedes zu kommentieren.
Sie werden viel mehr Kommentarzeilen als eigentliche Programmzeilen in
Ihrem Code haben.
Das mache ich nur jetzt noch nicht, weil dann Sie können sich
vorstellen, wie die Folien dann aussehen.
Gut.
Das war die Fallbeschleunigung.
Das, würde ich sagen, waren die drei einfachen Sachen.
Jetzt kommen wir zu den schwierigen.
Eine Methode, die für eine Sekunde eine Kraft F ansetzt.
Sie müssen nicht die Befehle dazu schreiben, sondern nur die Signatur.
Nur, welche Modifikatoren Sie dieser Methode verpassen würden.
Ich nenne die mal ApplyForce.
Und Sie sagen mir jetzt die fünf Bestandteile, die Sie gestern alle
auswendig gelernt haben, für diese Methode auf.
Nicht Static, weil es auf ein konkretes Masseobjekt wirkt und nicht
auf alle.
Void, genau.
Das ist eine Methode, die das Objekt verändert.
Die berechnet ja nichts.
Habe ich schon vorgegeben, genau.
Doch.
Gucken Sie mal.
Eine Methode, die für eine Sekunde eine Kraft F ansetzt.
Nee, die Kraft kommt von außen.
Wie würden Sie es machen?
Was ist denn eine Kraft physikalisch?
Eigentlich wieder ein Vektor, aber weil wir hier im Grundkurs sind,
sagen wir mal nur ein Double.
F klein oder groß?
Ist wieder kompliziert, also geben wir dem mal einen anständigen
Namen.
Ja, ist Englisch für Kraft, sorry.
Das sind alle, die wir brauchen, genau.
So.
Und jetzt müssten Sie eigentlich Java-Befehle hinschreiben, die M und
V so manipulieren, dass das Objekt hinterher so aussieht, als hätte
eine Sekunde lang diese Kraft gewirkt.
Wie würden diese Befehle aussehen?
Müssen Sie jetzt nicht exakt sagen, sondern was müssen Sie da
mathematisch tun?
Wie hängen denn Kraft und M und V überhaupt zusammen?
Gibt's da irgendwas?
Ja?
Finde ich gut, aber wir haben kein A.
Ja?
Vorsicht, da betreten Sie jetzt ganz dünnes Eis.
A ist, oder V ist...
V ist A mal T, in welcher Situation?
Das ist nicht immer so.
Das ist nur bei einer ganz bestimmten Form von Bewegung so.
Ja?
Bei einer gleichmäßig beschleunigten Bewegung, genau.
Haben wir das hier?
Genau.
Feste Zeit und feste Kraft passt genau auf diese Situation.
Und dann können Sie tatsächlich...
Sie müssen das dann noch nach V auflösen und dann kriegen Sie eine
einfache Formel mit einem Bruch drin und dann addieren Sie das einfach
auf V drauf.
Wenn das jetzt nicht eine gleichmäßig beschleunigte Bewegung wäre, was
müssten Sie denn dann tun?
Wie hängen V und A denn dann zusammen?
Wie hängen A und V überhaupt zusammen allgemein?
Wenn Sie nichts weiter wissen über Ihr Objekt.
Genau.
A ist die Ableitung von V über die Zeit.
Und wenn Sie jetzt aber das V in Ihrer Methode haben, wie drücken Sie
das denn über das A aus?
Also wenn das eine die Ableitung von dem anderen ist, was ist denn
dann die Umkehrung?
Das ist die Umkehrung von der Ableitung.
Mathevorkurs.
Ja?
Die Stammfunktion.
Genau.
Oder das Integral.
Und das erspare ich Ihnen jetzt.
Genau.
Deshalb hier nur den Rumpf.
Okay.
Das wäre die Methode, um eine Kraft wirken zu lassen.
Eine Methode, die einen Körper der Masse m gleich 1 mit
Geschwindigkeit V gleich 0 erzeugt.
Das ist das Letzte, was wir hier brauchen.
Diktieren Sie mir mal eine nette Signatur dafür.
Mass, create, mass, Klammer auf, Klammer zu, Semikolon.
Okay.
Public ist hier Modifikator.
Sie setzen die auf Static.
Warum?
Ist richtig, aber warum tun Sie das?
Ja.
Wenn Sie es nicht machen, brauchen Sie schon ein Masseobjekt, bevor
Sie überhaupt eines erzeugen können.
Ist irgendwie physikalisch doof.
Deshalb Static.
Zweiter Grund wäre, Sie erzeugen ein neues Objekt, das ist unabhängig
von allen anderen Objekten, die Sie schon haben.
Auch aus dem Grund ist hier Static die einzig richtige Lösung.
Was ist denn dieses Mass hier?
Wo kommt das her und wieso muss das da hin?
Der kriegt eine Referenz auf das neu erzeugte Masseobjekt zurück.
Und das ist der Rückgabetyp.
Kennt Java den schon?
Oder müssen Sie den irgendwo deklarieren?
Das ist eine Scherzfrage irgendwo.
Natürlich kennt Java den schon, wir deklarieren ihn ja gerade.
Das ist weniger scherzhaft, als es aussieht.
In gewissen Programmiersprachen wie C wird sich der Compiler weigern,
ein Objekt von einem Typ zu benutzen, den Sie gerade deklarieren.
Und dann brauchen Sie ein spezielles Schlüsselwort, mit dem Sie dem
Compiler sagen können, das ist aber schon okay, auch wenn das noch
nicht da ist, tu mal so, als wäre es.
Bei Java hat man das vereinfacht und sobald da oben ein Public Class
Mass auftaucht, weiß Java, es gibt ein Mass-Objekt oder eine Mass
-Klasse.
Okay, da würde ich jetzt aber schon mal sagen, probieren wir doch mal,
da auch den Rumpf zuzuschreiben.
Erstmal, ist das jetzt fertig oder muss ich noch Parameter dazugeben?
Ist ja der vierte Bestandteil von der Signatur, Parameter oder nicht?
Nein, weil in der Aufgabenstellung ja vorgegeben ist, was in dieses
Mass -Objekt jetzt rein soll.
Wie machen Sie es?
Welche Befehle würden Sie da jetzt reinschreiben?
Sie sollen einen neuen Massekörper erzeugen und den zurückgeben.
Ich könnte, probiere ich das mal, this.v="0", this.m="1", war glaube
ich vorgegeben und was geben Sie dann zurück?
Doch, Sie müssen ein Objekt vom Typ Mess zurückgeben, this return
this.
Okay, das ist erstmal an einer Stelle syntaktisch falsch und dann ist
es gravierend semantisch falsch.
Und es ist auch noch eine Sicherheitslücke.
Klären wir das mal alles auf.
Das Problem ist, es ist schon irgendwie richtig, aber es passieren
Dinge, die dem physikalischen Konzept, das dahinter steht,
widersprechen.
Und an einer Stelle, wie gesagt, verursachen Sie eine
Sicherheitslücke, die nicht so sichtbar ist.
Ja?
Das ist das erste.
Sie sind statisch, also this gibt es schon mal gar nicht.
Nee, das muss ja gar nicht aus einem Objekt rauskommen.
Gibt kein this.
Aber stellen Sie sich mal vor, wir hätten das so gemacht und es gäbe
ein this.
Was wäre denn dann das Problem?
Das wäre jetzt syntaktisch richtig, das würde der Compiler
akzeptieren.
Aber Sie verändern, der Funktionsname suggeriert ja, dass Sie ein
neues Objekt erzeugen und Sie manipulieren nicht mal nur dieses
Objekt, sondern das ist noch viel schlimmer.
Sie tun so, als wäre dieses Objekt das neue, das Sie erzeugen.
Und die Sicherheitslücke besteht darin, dass Sie Ihren Kasten
rausgeben.
Den ganzen Kasten.
Das sollten Sie niemals tun.
Return this ist absolutes No-Go.
Damit heben Sie alle private Sachen auf, die Sie vorhin getan haben.
Jemand, der diese Referenz hat, kann darauf zugreifen.
Okay, also tun wir das alles wieder weg.
Und das ist eine statische Methode und this gibt es nicht.
Aber trotzdem brauchen wir irgendwas, was wir mit Return zurückgeben
können.
Wie kriegen wir es?
Genau, Sie müssen überhaupt erstmal eine neue Masse erstellen.
Die nenne ich auch mal so.
Also ich habe die jetzt noch nicht geschrieben, die Set-Methoden, aber
ich tue mal so, als hätte ich sie.
Was setzen Sie da ein?
Und dann Return new.
So ist es richtig.
Alle damit einverstanden?
Genau, da sollte noch ein new dazu.
Das habe ich jetzt aber glaube ich vergessen.
Sie hatten es, glaube ich, diktiert.
So, alle einverstanden?
Es wäre schöner, wenn wir einen Konstruktor hätten, finde ich auch.
Wir haben ihn noch nicht, aber ich tue mal so, als wäre er da.
Das wäre doch viel besser.
Dafür müssten wir halt einen Konstruktor schreiben, aber haben wir
halt nicht.
Was ist denn damit?
Das ist auch keine einfache Frage.
Syntaktisch richtig oder syntaktisch falsch und dann unabhängig davon,
semantisch sinnvoll oder nicht.
Und dann unabhängig davon, style-guide-konform oder nicht.
Was war die Regel für private?
Wer darf auf private zugreifen?
Das geht.
Warum?
Wir greifen von außen in dieses Objekt rein, aber warum dürfen wir
das?
Wir sind in derselben Klasse.
Die Regel für private war, die Klasse darf auf sich selber zugreifen.
Auch wenn das ein anderes Objekt ist.
Es ist die gleiche Klasse und ich darf.
Semantisch.
Ist das in Ordnung oder nicht?
Machen wir irgendwas kaputt?
Verletzen wir Konsistenzregeln?
Ist das eine Sicherheitslücke?
Darf das Objekt neu, was ich da habe, demjenigen vertrauen, der gerade
darin rumschreibt?
Ja, weil das bin ich selbst.
Ich vertraue mir mal.
Das ist auch semantisch okay.
Von der Effizienz her.
Besser oder schlechter als Get-und-Set-Methoden?
Etwas besser, weil ich keinen Methodenaufruf habe.
Die Zuweisung brauche ich sowieso, egal wie ich das mache.
So, und jetzt vom Style-Guide her.
Erlaubt oder nicht?
Und die Frage können Sie nur beantworten, wenn Sie die Conventions
-Folien auf dem Ilias-Kursraum durchgelesen haben.
Okay, unabhängig davon.
Das stimmt, das habe ich jetzt falsch.
Obwohl, das wäre nicht mal ein Fehler gewesen, weil ich teile ja nicht
durch den Kram.
Aber trotzdem, man sollte immer klar machen, dass das Doubles sind.
So, aber trotzdem.
Direktes Rumschreiben in meinem eigenen Objekt, das ich zugreifen
darf, weil ich derjenige bin, der es konzipiert.
Okay oder nicht?
Ich sage, es ist okay, aber ich werde nachher, wenn die beiden Tutoren
kommen, die vielleicht näher an der Programmieren-Vorlesung dran sind
als ich, auch nochmal fragen, ob das okay ist.
So, alle einverstanden?
Das war ja der letzte Schritt in der Lösung.
Nein, wir können THIS nicht benutzen, weil wir gar kein Objekt haben,
zu dem diese Methode gehört.
Schauen Sie sich dieses Bild nochmal an.
Hier.
Diese Methode, die wir gerade schreiben, ist das gelbe hier oben.
Und da gibt es kein X und kein Y und kein Z, weil wir außerhalb von
dem Kasten sind.
Und es gibt auch kein THIS, weil wir überhaupt nicht in einem Kasten
drin sind.
Genau, da müssen Sie sich auch nicht so den Kopf drüber zerbrechen,
weil...
Das ist jetzt meine Musterlösung.
Weil Sie der Java-Compiler bzw.
Eclipse mit einem roten Strich schon darauf hinweisen wird, wenn Sie
THIS benutzen, wo es kein THIS gibt.
Okay, also ich habe es fast genauso gelöst.
Die Rumpfbefehle habe ich wieder weggelassen und da habe ich das halt
auch mit englischen Wörtern beschrieben.
Ansonsten ist das die gleiche Lösung wie die, auf die wir gekommen
sind.
Ich habe es jetzt nicht auf private gesetzt, müsste man eigentlich
auch noch machen, wenn man sich an die Konventionen hält.
Das ist eine mögliche Lösung für das Problem.
Fragen dazu?
Gut, dann würde ich mit Ihnen jetzt in 20 Minuten noch kurz
durchgehen, welche Typen von Variablen es in Java gibt.
Static und nicht-static haben wir eben schon gesehen.
Und kurz den Lebenslauf durchgehen.
Lebenslauf ist jetzt ein etwas komischer Begriff.
Mit Lebenslauf ist gemeint, wann wird die Variable erzeugt, wann
erscheint sie im Speicher, wann darf man sie benutzen, wann ist sie
wieder weg.
Da gibt es fünf verschiedene Situationen, die wir untersuchen werden.
Und für jede dieser Situationen stelle ich mir diese vier Fragen.
Wann wird es deklariert?
Wann kommt was rein?
Wann wird damit gearbeitet?
Wann wird es entfernt?
Und da müssen Sie auch ein paar Fachbegriffe lernen.
Also der allereinfachste Fall ist das, was Sie hier sehen.
Sie deklarieren eine Variable.
Sie schreiben Sachen rein.
Sie rechnen damit.
Sie geben es aus.
Und im Grunde da hinten, wo die Klammer schließt, wird die Variable
aus dem Speicher entfernt.
So haben wir bisher immer gearbeitet, aber sobald Sie Klassen,
Objekte, Statisch und New haben, können diese Lebensläufe anders
aussehen.
Und das gehen wir für diese fünf Typen von Variablen durch.
Einmal haben Sie lokale Variablen.
Lokal heißt auf einen bestimmten Ort beschränkt.
Das Gegenstück dafür ist global.
Nur globale Variablen gibt es in Java nicht.
Lokal heißt, das ist innerhalb einer Methode oder eines Code-Blocks
deklariert und nur da sichtbar.
Das ist eigentlich der Normalfall, den Sie immer haben, wenn Sie
einfach int irgendwas hinschreiben.
Dann kennen Sie jetzt ja schon Parameter.
Das sind Variablen, die in der Signatur einer Methode auftauchen und
vom Aufrufer gegeben werden.
Dann gibt es umgekehrt den Rückgabewert.
Das ist das, was Sie mit dem Return-Befehl zurückgeben.
Das ist streng genommen auch eine Variable.
Und dann kennen Sie jetzt zwei Typen von Attributen.
Attribut ist eine Variable, die in einer Klasse oder einem Objekt
auftaucht.
Und da haben wir jetzt gesehen, es gibt objektgebundene Attribute in
den Kästen und es gibt statische Attribute außerhalb der Kästen, die
für alle Objekte geteilt werden.
Diese fünf Typen von Variablen beschreibe ich Ihnen mal kurz.
Einfachster Fall, lokale Variable wie hier dieses int a.
Das lebt ab dem Zeitpunkt, wo es deklariert wird und verschwindet an
der Stelle, wo die Methode oder der Code-Block aufhört, wo es
deklariert wurde.
Ganz einfach.
Das Rote ist der Bezeichner für die Variable und außerhalb dieser
geschweiften Klammern gibt es das kleine a nicht.
Wenn Sie darauf zugreifen, der Java-Compiler ist nicht so clever, der
sagt Ihnen nicht, sorry, das ist außerhalb von dem
Sichtbarkeitsbereich, sondern der sagt Ihnen einfach nur a kenne ich
nicht.
Das gibt es nur in diesem Block.
Parameter werden in der Signatur einer Methode deklariert und werden
nicht von der Methode selbst, sondern vom Aufrufer der Methode mit
Werten gefüllt.
Das heißt, es ist zwar syntaktisch erlaubt, aber Sie sollten a und b
nicht mit Werten beschreiben in dieser Situation, sondern Sie haben a
und b von außen bekommen.
Derjenige, der die Methode aufgerufen hat, hat da Werte eingefüllt und
die müssen Sie irgendwie verwenden.
Sichtbar sind die Parameter während der Methode, also von dieser
öffnenden Klammer hier bis zu der schließenden Klammer da unten.
In der ganzen Methode können Sie a und b verwenden.
Dieser Vorgang, dass das im Speicher angelegt und mit Werten gefüllt
wird, das passiert bevor die Methode ausgeführt wird.
Und erst nachdem die Methode abgeschlossen ist, entweder durch Return
Statement oder durch die geschlossene Klammer, erst dann werden die
beiden wieder aus dem Speicher entfernt.
Das ist der Lebenslauf eines Parameters.
Da müssen Sie übrigens zwei Fachwörter unterscheiden.
Der Parameter ist die Variable, die Sie hier deklarieren, das kleine
a.
Und das Argument, das ist auch ein Fachwort, das ist der konkrete
Wert, den der Aufrufer da reingeschrieben hat.
Also wenn Sie z.B.
die Methode Sinus x haben, dann ist x der Parameter und wenn ich Sinus
von 15 berechne, dann ist 15 das Argument, was da konkret drin steht.
Später in der Vorlesung müssen Sie das unterscheiden, jetzt im Vorkurs
ist es noch egal.
Der nächste Typ ist der Rückgabewert.
Das ist ein relativ komplizierter Typ von Variable.
Der hat nicht mal einen Namen.
Der wird nur deklariert, was er ist und was drinstehen darf, aber er
bekommt keinen Namen.
Das liegt daran, dass Sie ihn nirgends erzeugen, sondern Sie schreiben
einfach nur Return irgendwas.
Dieses irgendwas wird dann zu dem Rückgabewert und an den Aufrufer
übergeben.
Der Lebenslauf so einer Variable ist extrem kurz.
Das ist die kürzeste Variable, die Sie überhaupt haben können.
Die lebt nur von diesem einen Moment, wo das Return-Statement hier
passiert und da unten der Return-Wert der Variable in S zugewiesen
wird.
Nur für diesen einen kurzen Moment existiert der Rückgabewert und wenn
Sie die Summe einfach so aufrufen, ohne das in S reinzuschreiben, dann
existiert er nicht mal dafür.
Dann wird es sofort weggeschmissen.
Das demonstriere ich Ihnen gleich an einem Beispiel, aber im Moment
müssen Sie sich so vorstellen, dass das eine Speicherzelle ist in
Ihrem Rechner, deren einziger Zweck darin besteht, dieses A plus B zu
speichern in dem kurzen Moment, wo die Methode aufhört und dieses
Double S anfängt.
Verstehen Sie das, dass man dafür eine extra Speicherzelle braucht.
Ich darf nicht einfach das eine abrechnen und das andere anfangen.
Da muss irgendwie eine Kommunikation stattfinden und der Rückgabewert
sagt Ihnen, was da kommuniziert wird.
Okay, der vierte Datentyp sind die gewöhnlichen objektgebundenen
Attribute.
Kennen Sie schon.
Die werden in einer Klasse deklariert und aufgelistet und jedes Mal,
wenn Sie mit new ein Objekt neu erzeugen, bekommt jedes neue Objekt
sein separates Attribut.
Typischerweise, das Dialog erzwingt das auch, sind die private und Sie
versorgen die im Konstruktor mit Startwerten.
Also Sie machen nicht sowas wie int a gleich 5, sondern Sie
deklarieren das int a im Objekt und im Konstruktor erst schreiben Sie
einen Startwert rein.
So müssen Sie das ab jetzt immer tun.
Jedes Objekt hat seine eigenen Attribute im Speicher.
Der Styleguide erzwingt, dass sie private sind.
Sie sollen nur über Get und Set Methoden manipuliert werden und
innerhalb dieser Methoden greifen Sie über Objektnamen und den
Referenzpunkt darauf zu.
So wie hier.
Eigentlich nicht so wie hier, weil das ist wieder so eine Manipulation
von außen.
Die Objektattribute verschwinden in dem Moment, wo das Objekt gelöscht
wird.
Wann passiert denn das?
Das sehen Sie im Programmcode in der Regel gar nicht.
Wann wird denn ein Objekt überhaupt gelöscht?
Genau, das ist eine sehr gute Antwort.
Wenn der Garbage Collector anspringt, wann tut er das?
Das wissen Sie nicht.
Sie haben eine Information, er wird es dann tun, wenn keine Referenz
mehr auf das Objekt existiert.
Aber wenn Ihr Garbage Collector langsam ist oder Ihr Rechner gerade
mit irgendwelchen anderen Sachen beschäftigt ist, kann das ein ganz
anderer Zeitpunkt sein als der Zeitpunkt, wo Sie die Referenz entfernt
haben.
Wenn Sie jetzt an die typischen Situationen denken, wo Sie Objekte
entfernen oder nicht.
Zum Beispiel, wenn ein Array umkopiert wird oder wenn Sie es
verlängern oder wenn Sie ein Stück da rauslöschen, sehen Sie, dass
diese Operationen sehr, sehr häufig passieren.
Die Garbage Collection ist intelligent.
Wenn Sie 10.000 Objekte in Ihrem Array haben und Sie verlängern das,
dann wird jetzt Java nicht erst jedes einzelne löschen und jedes
einzelne dann wieder anlegen, sondern das erst machen, wenn Ihre
Operation komplett abgeschlossen ist.
Darüber haben Sie leider keine Kontrolle.
Und es hängt auch davon ab, wo Ihr Java-Programm läuft.
Wenn Ihr Java-Programm in einem Webbrowser läuft, der nur ganz, ganz
wenig Speicherplatz zur Verfügung hat, weil er vielleicht auf einem
Smart -Device ist, dann kann es sein, dass sofort entfernt wird.
Wenn Ihr Java-Programm auf einem PC läuft mit 16 GB drin und einer
hochoptimierten Java-Virtual Machine, dann kann es sein, dass
überhaupt niemals irgendetwas gelöscht wird, weil es einfach Zeit
kostet und Sie brauchen den Platz gar nicht.
Da haben Sie gar keine Kontrolle drüber.
Deshalb habe ich hier einfach hingeschrieben, Attribute werden
gelöscht.
Wenn das Objekt gelöscht wird und wann das passiert, wissen wir halt
nicht.
Genau.
Hier in diesem Beispiel ist das Rote, dieses Punkt X, das ist Ihr
Objektattribut.
Das V selbst ist eine lokale Variable, die ist dann weg, wenn die
Klammer hier zugeht.
Verstehen Sie das?
Okay, dann das Letzte, die statischen Attribute.
Die werden auch innerhalb der Klasse deklariert und haben halt diesen
Modifikator static davor.
Statische Attribute haben einen separaten Lebenslauf.
Die sind in dem Moment da, wo Sie Ihr Programm starten.
Egal, ob Sie mit new überhaupt ein Objekt erzeugen oder nicht.
Sie sind unabhängig von allen Objekten im Speicher.
Sie sind, wenn Sie public sind, für alle Teile des Programms sichtbar.
Sie werden über den Klassennamen und den Referenzpunkt zugegriffen.
Typischer Zugriff zum Beispiel Math.p.
p ist eine statische Konstante in Ihrer Klasse Math.
Und Sie können die benutzen, auch wenn Sie noch kein einziges Objekt
vom Typ Math angelegt haben.
Das gehört zur Klasse.
Es ist an die Klasse gebunden.
Aus philosophischer Sicht werden statische Attribute niemals gelöscht.
Beziehungsweise halt dann, wenn das Betriebssystem das Programm aus
dem Speicher entfernt.
Aber ansonsten sind die immer da.
Die können Sie nicht löschen.
Sie brauchen auch kein Objekt erzeugen.
Und bei Konstanten oder bei Sinusfunktionen und so will man das ja
auch so haben.
Das sind Dinge, die existieren einfach so.
Ohne, dass sie zu irgendetwas gehören.
Das sind die statischen Attribute.
Die müssen Sie immer dann verwenden, wenn Sie etwas teilen.
Wenn etwas für alles gleich sein soll.
Und später, wenn Sie etwas effizient ausrechnen wollen.
Wenn Sie ein Array von 10 Billionen Zahlen haben, dann tun Sie das auf
gar keinen Fall in ein objektgebundenes Attribut.
Sondern das muss statisch sein.
Da darf die Speicherverwaltung überhaupt nicht anfangen, irgendwas hin
und her zu schieben.
Das wird sie vielleicht trotzdem tun, aber das ist ein Problem von
Java.
Und statisch ist das Beste, was Sie da tun können, um das
auszuschalten.
Okay, das waren die fünf Typen von Variablen, die es in Java gibt.
Lokale Variablen, Parameter, Rückgabewerte, Attribute und statische
Attribute.
Andere kennen wir nicht und andere gibt es auch nicht.
Ich mache mit Ihnen jetzt zum Schluss, bevor wir zum Blatt kommen,
eine lange Aufgabe.
Das heißt, ich spiele jetzt für Sie den Showmaster und gehe an die
Tafel und spiele Ihnen vor, wie das im Speicher aussieht, wenn Sie
dieses Programm hier ausführen.
Aber Sie diktieren mir, was ich da in den Speicher reinschreiben soll.
Gucken Sie, bevor ich da anfange, dieses Programm jetzt mal ganz in
Ruhe an.
Da gibt es bestimmte Attribute.
Da gibt es eine klasse Aufgabe.
Da gibt es eine Methode Test.
Und es gibt die allgegenwärtige Public Static Void Main, die irgendwas
damit macht.
Ich habe ein paar fiese Tricks eingebaut.
Also zum Beispiel, die Public Static Void Main gibt...
Das schneiden wir aus der Aufzeichnung raus, ist kein Problem.
Zum Beispiel, die Public Static Void Main ist ein Bestandteil der
Klasse Aufgabe.
Und innerhalb der Public Static Void Main erzeugen Sie ein Objekt vom
Typ Aufgabe.
Geht sowas überhaupt?
Oder geht das nicht?
Kann ich in einem Objekt, in dem eine Methode ist, Befehle
reinschreiben, die dieses Objekt überhaupt erst erzeugen?
Darf ich das oder darf ich das nicht?
Das ist keine philosophische Frage, sondern das können Sie mit einem
ganz einfachen Argument bejahen oder verneinen.
Ja?
Jawohl.
Und das hat jetzt auch nichts damit zu tun, dass es die Main ist,
sondern es ist statisch.
Das heißt, es ist da, bevor Sie überhaupt irgendeine Aufgabe erzeugt
haben.
Deshalb ist das syntaktisch korrekt erlaubt.
In anderen Programmiersprachen drückt man sich um dieses Problem.
Also in C++ haben Sie einfach eine Main-Funktion, die einfach zu
keinem Objekt gehört.
In Java gehört die auch nicht zu irgendeinem Objekt, aber sie gehört
zu dieser Klasse.
Wegen Static ist sie aber schon da, bevor die Objekte dieser Klasse
erzeugt werden.
Okay.
Also, eine Klasse.
Zwei Attribute.
Eine Methode, eine statische Methode.
Und jetzt male ich meinen Speicherbereich mal hin.
Und wir versuchen, den schrittweise in der Reihenfolge, wie die Sachen
hier erzeugt werden, mit Inhalten zu füllen.
Wir gehen dabei davon aus, dass die Speicherverwaltung optimal ist.
Das heißt, wenn irgendetwas keine Referenz mehr hat, wird es gelöscht.
Wo fängt denn das Programm überhaupt an?
Und was ist zu dem Zeitpunkt im Speicher?
Wo fängt ein Java-Programm an?
Da möchte ich jetzt aber 100 Finger oben sehen.
Naja, zwei sind auch gut, ja?
Beim Aufruf der Main-Methode.
Also hier, bei dieser öffnenden Klammer, fängt Ihr Programm an.
Was ist zu diesem Zeitpunkt im Speicher?
Eine ganze Menge.
Listen wir es mal auf.
Ja?
Nur eins.
Das static int j gleich 2 ist im Speicher, weil es statisch ist.
Und deshalb von der Java Virtual Machine angelegt worden ist, bevor
die Main-Methode kommt.
Noch mehr?
Da ist noch eine ganze Menge mehr im Speicher.
Überlegen Sie mal.
Ja?
Das args ist auch schon.
Was für ein args?
Ich habe sie hier ein bisschen reingelegt.
Was meinen Sie?
Ich habe hier gar kein args.
Sie meinen schon das Richtige, aber ich war fies, ich habe es in der
Aufgabe anders genannt.
Das s, genau.
Das hier auch.
Ich habe es deswegen anders genannt, damit Sie sehen, dass das nichts
mit diesem public static void main zu tun hat, sondern...
das ist ein Parameter.
Und sobald diese Methode ausgeführt wird, ist Ihr Parameter da.
Was muss ich in meinen Speicher malen?
Ja?
Eine Referenz?
Wo irgendwelche Strings drin sind, genau.
Das ist ja nicht nur ein String, das ist ein Feld von Strings.
Wie viele das jetzt sind, weiß ich nicht.
Das hat derjenige entschieden, der ihr Programm aufgerufen hat.
Das kann auch leer sein.
Ist das alles, was da ist?
Oder noch mehr?
Ich behaupte, da gibt es noch mehr.
Ja?
Was für eine Klasse.
Ja, Sie haben eine Reihe von Hilfsobjekten, auch die Mathebibliothek,
da ist das Pi halt schon da.
Das schreibe ich jetzt nicht alles an, das sind ja Millionen Sachen.
Nur was hier im Quelltext ist.
Ja?
Die main Methode sollte auch irgendwo im Speicher sein, sonst wird es
ein bisschen schwer, die auszuführen.
Genau.
Die ist separat, die ist statisch, die ist irgendwo im Speicher, die
gehört zu nichts anderem.
Ist jetzt alles da?
Ich denke schon.
Jetzt können wir den ersten Befehl ausführen.
Aufgabe a gleich new Aufgabe.
Was taucht im Speicher auf?
Jetzt sind wir in der ersten Zeile hier.
Was ist denn in so einer Aufgabe alles drin?
Ich sehe gerade, ich muss eine Speichererweiterung dran machen.
Das reicht nicht mehr.
So.
Was taucht alles auf in dieser einen Zeile?
Ja?
Genau.
Zunächst einmal habe ich ein Objekt vom Typ Aufgabe.
Füllen wir das erstmal aus.
Das notiere ich auch mal, dass das jetzt ein Objekt ist, das einen
festgelegten Datentyp hat.
Was kommt da rein?
Was hat der new Befehl alles erzeugt?
Ja?
Das Double A.
Das hat auch gleich am Anfang den Wert 1.
Ich war schlampig, eigentlich gehört das in den Konstruktor, aber ich
war zu faul.
Die Methode Test.
Die ist objektgebunden und kommt deshalb auch in diesen Kasten.
Genau.
Noch mehr?
Ich muss selber nochmal durchgehen.
Nee, mehr nicht, weil die Public Static Void Main ist statisch.
Und das J oben ist statisch.
Das kommt nicht in den Kasten.
Wo kommt denn das große A hin?
Was ist das für ein Typ von Variablen und wo kommt der hin?
Ja?
Mit der Referenz haben Sie recht, mit dem neben dem S.
Warum würden Sie das neben das S schreiben?
Wenn Sie das jetzt richtig begründen, mache ich es.
Sondern?
Ja, was ist denn das für ein Typ?
Also Sie haben jetzt gesagt, was für ein Datentyp das ist.
Das ist eine Referenz.
Aber was für eine Sorte ist es von den fünf, die ich Ihnen vorhin
aufgelistet habe?
Es ist eine lokale Variable, die zur Methode Main gehört.
Die gehört hier hinten wirklich an das S dran.
Also so.
Die beiden gehören eigentlich da rein.
Wenn Sie es ganz genau nehmen.
Ich habe nur keinen Platz mehr.
Alle einverstanden?
Gut.
Dann können wir zum nächsten Befehl gehen.
Da passieren ganz viele Sachen gleichzeitig.
Versuchen wir die mal zu ordnen.
Da wird eine Methode aufgerufen.
Die bekommt als Argument die Minus 3.
Die landet da oben im Parameter B und gibt einen Rückgabewert zurück,
der in das W geschrieben wird.
Und in der Methode selbst wird auch noch Zeug erzeugt.
Was passiert denn da zuerst?
Von allen diesen Sachen.
Zuerst taucht die Minus 3 irgendwo auf.
Genau.
Da haben wir also erstmal dieses kleine B.
Das kriegt den Wert Minus 3.
Die Methode Test ist schon da.
Jetzt sind wir hier bei dieser öffnenden geschweiften Klammer.
Da ist die Java Virtual Machine jetzt hingegangen und gibt die
Ausführung dahin.
An der Stelle ist das B gleich Minus 3 im Speicher.
Was passiert dann?
Wo tue ich das hin?
Das wäre jetzt eine Möglichkeit, dass ich das da reinschreibe.
Da habe ich aber keinen Platz mehr.
Das wäre schon richtig.
Ich tue es deshalb unter das B.
Da habe ich jetzt ein Y gleich 0.
Y gleich A.
Ist das überhaupt ein zulässiger Befehl?
Syntaktisch, semantisch, Style-Guide-mäßig.
Alles korrekt?
Nein?
Ja?
Syntaktisch korrekt ist es.
A ist außerhalb der Methode, aber...
Ist das ein Problem?
Was ist A für eine Sorte von Variable?
Nee, A ist nicht statisch.
Das ist ein objektgebundenes Attribut.
Darf ich das benutzen oder darf ich nicht?
Genau.
Weil ich in einer nicht-statischen Methode bin.
Und jetzt kommt eigentlich der Style-Guide und ich müsste hier das
Punkt A hinschreiben.
Habe ich nicht gemacht, weil sonst hätte ich ja schon die Frage
beantwortet, wo das ist.
Okay, das ist syntaktisch richtig.
Y gleich A darf ich zuweisen.
Was muss ich dann hier reinschreiben?
Ja?
Die 1 da, genau.
Wird einfach der Wert kopiert.
Gut.
Y gleich Y plus B mal J.
Und Y ist die lokale Variable Y.
B ist der Parameter, da war eine Minus 3 drin.
Und J ist die statische Variable J.
Muss ich die irgendwie referenzieren?
Muss ich sagen, dass die aus der Klasse Aufgabe kommt?
Nein, weil ich bin in der Klasse Aufgabe drin.
Was kommt denn da raus?
Ach, da muss ich selber ein bisschen rechnen.
Minus 2?
Oder habe ich mich verrechnet?
0 plus Minus 3 mal die 2 sind...
Ne, sind Minus 6.
Oh ja, dann ist Minus 5, genau.
Ja, machen Sie das immer so im Kopf.
Ist gar nicht so einfach, das zu entscheiden.
Minus 5, alle einverstanden?
Okay.
Das Return Y mache ich für Sie, weil da passieren halt ein paar
Sachen, die nicht so einfach sind.
An der Stelle, Return Statement, wird die Methode abgebrochen.
Auch wenn das nicht am Ende der Methode wäre, sondern hier vorne, wird
die Methode an der Stelle abgebrochen.
An der Stelle taucht der Rückgabewert auf.
Der hat gar keinen Namen.
Da kommt jetzt einfach diese Minus 5 rein.
Dann wird die Methode beendet.
Beendet heißt, alles was lokal oder Parameter oder referenziert über
diese Methode war, verschwindet.
Was muss ich aus dem Speicher entfernen?
Also ich streiche es nicht wirklich weg, sondern ich streiche es
vielleicht durch.
Ja.
Zunächst einmal das Y, weil das eine lokale Variable war.
Dann...
noch mehr.
Ja.
Das B, weil es ein Parameter war.
Noch mehr.
Ja.
Ne, die ist noch da.
Die könnte ich ja jetzt von einem anderen Objekt aus auch nochmal
aufrufen.
Der Programmcode der Funktion, der ist noch da.
Ich muss jetzt selber mal gucken.
Ich glaube, mehr wird auch nicht gestrichen.
Oder finden Sie noch was?
Ne.
Gut.
Jetzt sind wir in dieser einen Mikrosekunde, wo die Methode beendet
ist...
und über dieses Gleichheitszeichen der Wert nach W übertragen wird.
Das heißt, da taucht jetzt ein W auf.
Das ist eine lokale Variable.
Die tue ich wie alles, was zur Main gehört, hier oben in die Ecke.
Und das kriegt die Minus 5.
Und in genau dem Moment verschwindet auch diese Hilfs-Speicherzelle
wieder aus dem Speicher.
Die hat nur für diesen einen Übertrag gelebt.
Okay?
Sind wir fertig?
Ja?
Nein?
Jetzt schließt die Main-Methode ab.
Und jetzt müssen wir ganz viel aus dem Speicher streichen, aber in der
richtigen Reihenfolge.
Was verschwindet zuerst?
Also, dass das jetzt die Hauptmethode ist, interessiert den Prozessor
überhaupt nicht.
Der sieht nur, da hat eine Methode aufgehört.
Was verschwindet, wenn eine Methode aufhört?
Ja?
Also zunächst mal verschwinden die lokalen Variablen.
W und A.
Damit ist auch dieser Pfeil weg.
Noch mehr?
Und machen Sie nur, was jetzt in diesem Zeitschritt verschwindet, noch
nicht die Sachen, die da dranhängen.
Ja?
S, weil es ein Parameter ist.
Damit geht auch dieser Pfeil weg.
Und jetzt?
Noch mehr?
Erstmal nicht noch mehr.
Das sind jetzt alle Sachen, die an die Main-Methode gebunden waren.
Und jetzt?
Jetzt warten Sie ein, zwei Sekunden und dann kommt die Garbage
Collection von Java und sagt was.
Genau.
Dann sagt die Garbage Collection, da ist ein Objekt im Speicher, das
hat keinen Besitzer mehr, das kommt weg.
Und dann sagt die Garbage Collection, oh, da ist eine Variable drin,
die kommt weg.
Und da ist Programm-Code drin, der kommt weg.
Und eigentlich kommt der ganze Kasten weg.
Und noch mehr?
Ja?
Der String-Array auch.
Das ist auch weg.
Genau.
Noch mehr?
Es ist ja nicht mehr so viel übrig.
Was ist mit j gleich zwei und was ist mit Main?
Das ist jetzt die philosophische Frage.
Und das da unten auch.
Genau.
Das sind beides statische Attribute, beziehungsweise statische
Methoden.
Und die Vorstellung ist, dass statische Sachen niemals verschwinden.
Natürlich wird ihr das Betriebssystem, den ganzen Speicher sowieso
leer machen, wenn ihr Programm fertig ist.
Aber aus Java-Sicht bleibt es sozusagen für immer und ewig da.
Okay.
Haben Sie Fragen zu dem, was ich Ihnen da gerade vorgespielt habe?
Das müssen Sie ab und zu auch selber mal tun.
Und dann ganz wichtig, weil Sie Informatik studieren.
Das ist ein nettes Bild.
Das sieht in Ihrem Computerspeicher nicht so aus.
Sondern die Speicherverwaltung wird es linear anordnen.
Und später werden Sie lernen, dass das auf einem sogenannten Stapel
angeordnet wird.
Das sieht völlig anders aus, als auf diesem Bild.
Das ist nur eine Visualisierung, aus der Sie ablesen können, wann was
entfernt oder neu hingeschrieben wird.
Auf gar keinen Fall dürfen Sie sowas in einer Klausur bei uns malen.
Das ist genau so, wie wenn Sie in einer Mathematikklausur irgendwas
mit einem Bild begründen.
Nach dem Motto, die Funktion hat ein Minimum, weil guck mal, Bild.
Das müssen Sie, wenn Sie in einer Klausur sitzen, mit Definitionen und
Sätzen und Formeln begründen.
Das lernen Sie später in der Vorlesung.
Jetzt bei den Aufgaben vom Vorkurs dürfen Sie es so machen.
Und die Aufgabe ist auch heute so designt, dass alle diese Typen mal auftreten.