Ja, ihr kennt mich gleich von den anderen Veranstaltungen mit Level 1,
Selbsttests, Level 2 wird ab nächster Woche auch online gehen,
aber heute bin ich in einer anderen Mission da.
Ich möchte euch ein bisschen herausfordern und dazu möchten wir euch ein neues Spiel vorstellen,
was auch in dieser Woche wahrscheinlich gestartet wird.
Es wird eher auf individueller Basis sein und das Ganze nennt
sich Gast My Object, deswegen hier GMO.
Die Idee dahinter ist relativ einfach und simpel. Ihr habt letzte Woche rausgefunden,
dass es Interfaces zum Beispiel gibt, dass man verschiedene Möglichkeiten hat,
etwas zu implementieren und die gleiche Funktionalität eigentlich dadurch gesichert wird.
Was wir uns überlegt haben, ist,
dass man das auch als Spiel verfassen kann,
dass ihr eine Challenge bekommt, ihr müsst mich anschreiben,
dann bekommt ihr eine Klasse, die so wie die Obere hier keine Source vorhanden hat.
Das heißt, man kann nicht reinschauen, man kann,
wenn man doppelt klickt, sich nur die Dokumentation anschauen dazu.
Und die Idee dabei ist folgendes, dass man sich ein Exemplar erstellt aus der Klasse.
Das machen wir einfach mal. Wir übergeben eine Vier,
also man soll eben, wie man das,
glaube ich, ganz gut lesen kann, ja,
man soll eine positive Zahl übergeben, also wir nehmen mal die Vier,
haben jetzt dieses Exemplar erstellt und können dann dementsprechend Hier eine Methode aufrufen.
Auch hier muss eine ganze Zahl übergeben werden.
Also es wird sich jedes Mal ändern für die einzelnen Aufgaben.
In diesem Fall ist es so, wir geben jetzt mal
eine 2 an und bekommen einen Wert der True zurückgibt.
Gut, jetzt ist die Aufgabe an euch sozusagen,
um zu überlegen, wann kommt True raus, wann kommt Falls raus?
Und wie könnte man das implementieren? Also wir müssen jetzt
einfach hier ein paar Tests ausführen, um rauszufinden,
was passiert, wenn ich eine 5 angebe.
Dann wird es Falls. Wenn ich eine 4 angebe,
was wird dann rauskommen? Vielleicht hat schon die erste Idee,
also 2 war True,
5 war Falls
Fear is true. Ähm, weil eins,
auch true, eine Idee, was das sein könnte,
was dahinter für einen Mechanismus läuft, jemandem vorschlagt.
Wie bitte? Gerade ungerade. Also ich habe
auch eine Eins angegeben, da war es False.
Gerade ungerade ist, glaube ich, nicht ganz richtig.
Gestellt von Frei. Bitte? Nee, auch nicht.
Wie war das? Das teilen wir am. Ja,
ich sehe schon, also es gibt da verschiedene Varianten,
was jetzt der Schritt wäre, um das rauszufinden, was genau ist.
Man müsste einfach noch ein bisschen mehr ausprobieren.
Müsste vielleicht mal sagen, ich nehme hier Eine 1. Und
gucke, was dann passiert. Also ändert sich dadurch das
Verhalten für die Klasse, beziehungsweise für das Objekt.
Wenn ich jetzt hier eine 4 eingebe, ist da jetzt ein anderes Ergebnis.
Vorher war es too, jetzt ist es false.
Also das heißt, da kann man so ein bisschen überlegen,
wie kann ich mit dieser Klasse, mit dem Objekt interagieren?
Und wie ändert sich das Zustand? Was ihr
nicht machen dürft oder was eben sozusagen eine Regel ist,
und die Regeln sind hier verfasst innerhalb dieses Readme-Text-Files.
Es wird so sein, dass ihr nicht den Objektinspektor benutzen dürft.
Alles andere ist natürlich dann durch die, dadurch,
dass die Source nicht vorhanden ist,
auch nicht möglich
Um hierzu jetzt mal die Auflösung zu geben, was gemacht wird,
ist einfach zu gucken, ist das ein Teiler?
Also die Zahl, die ich übergebe,
in der Methode ist das ein Teiler von dem,
was ich vorher in der Infrastrukturaufruf eingegeben habe.
Ja, und was interessant ist,
dass es einerseits hier so eine Lösung gibt mit einer Zeile.
Man kann allerdings auch eine Lösung finden,
die mehrere Zeilen natürlich hat, aber das gleiche Ergebnis liefert.
Also das ist genauso zu letzter Woche der Rückschluss zu Interfaces
beispielsweise. Ihr sollt euch überlegen, was ist die Möglichkeit
dieser Klasse und wie kann ich sie umsetzen?
Das sind die zwei Schritte und das wird diese Woche gestartet,
auch übers Kommen sie und wieder per Mail
Insofern hoffe ich einige Leute zu begeistern dafür. Ich glaube,
für Anfänger ist es eher so ein neues Draufschauen auf das bisher Gelernte für Fortgeschrittene.
Ist es vielleicht eine Herausforderung? Ich würde so sagen,
es ist nicht wirklich die Aufgaben anpasse an die Schnelligkeit und an die Situation,
wie die einzelnen Personen reagieren,
wie sie die Aufgabe lösen und was sie vielleicht mir dazu sagen,
ob es jetzt total leicht war oder total schwer.
Ja, also ich hoffe euch dafür zu gewinnen.
Ich hoffe, es ist ein bisschen ein anderer Ansatz,
um nochmal spielerisch daran zu kommen.
Und ich gehe davon aus,
dass ihr
diese Challenge akzeptiert
Gut, dann übergebe ich ein Axel. Jo. Alles klar.
Vielen Dank, Timo. Das ist eine sehr coole Aktion
. Ich glaube, das solltet ihr dann nochmal ausprobieren.
Ich muss einfach nur eine E-Mail an Timo schicken und dann
werdet ihr alles weitere erfahren, wie man weiter dranbleiben kann.
Sehr schön. Heute geht es auch wieder um Interfaces und Implementationen
von Interfaces. Das habe ich letzte Woche ja eingeführt,
dass man mit einem Interface eine Schnittstelle definieren kann.
Ein Verhalten, versprechen kann, wie eine Spezifikation und es dann
verschiedene Möglichkeiten geben kann, dieses Verhalten auch wirklich zu implementieren.
Das gucken wir uns an am Beispiel von Objektsammlungen.
Und das ist jetzt so ein Abschnitt, wo man sagen kann,
jetzt wird es langsam richtig spannend. Also wenn ich letzte Woche noch,
sagen wir, meine persönliche Leidenschaft für Interfaces hier in die Veranstaltung eingebracht habe und ihr damit leben müsst,
dass ihr relativ früh euch mit Interfaces auseinandersetzen müsst,
ist das jetzt so, dass selbst alle die,
die vielleicht nicht so begeistert sind von expliziten Schnittstellenbeschreibungen,
sagen werden, naja,
jetzt machen wir mal was richtig Nützliches.
Jetzt gucken wir uns nämlich Objektsammlungen an. Und Objektsammlungen sind,
ja, so ziemlich das Wichtigste in der Programmierung.
Also in fast jedem Kontext, in dem irgendein Problem programmtechnisch
gelöst wird, ist eine Sammlung von gleichartigen Objekten involviert.
Das lässt sich fast gar nicht vermeiden. Es ist also selten so,
dass man so mit so ein paar Schleifen und so ein paar Variablen,
wie ihr es bisher kennengelernt hat, auskommt,
sondern man braucht fast immer irgendwie eine Möglichkeit,
mehrere Dinge gleichartig zu behandeln,
zusammenzufassen und dann auch einheitlich zu manipulieren
Was wir uns heute ansehen werden, ist, wie man solche Dinge benutzt.
Es gibt da also tatsächlich in Java relativ schöne Sammlungskonzepte.
Und wir werden uns aber auch in diesem Semester,
in SE1, in zwei, drei Wochen ansehen,
wie man solche Sammlungen auch implementieren kann.
Das heißt, wir werden tatsächlich die Sammlung von Java sehr gut kennenlernen.
Zuerst aus Klientensicht heute und dann später auch aus Implementierersicht aus Dienstleistersicht.
Dann werden wir sehen, wie solche Dinge gebaut sind,
damit wir die Strukturen kennen von solchen Sammlungen und dann sie
auch kompetenter benutzen können.
Was wir uns erstmal ansehen, das ist sozusagen das Allereinfachste,
was man sich angucken sollte, wenn man sich mit Sammlungen beschäftigt.
Das sind Mengen und Wissen. Ihr werdet vermutlich
auch in der Mathematik euch mit solchen Konzepten beschäftigen.
In der diskreten Mathematik, im ersten Semester, teilweise auch.
Ich weiß nicht, wie weit ihr da schon seid,
aber werden also tatsächlich in der Mathematik durchaus verarbeitet,
diskutiert, auch in der theoretischen Informatiklisten und Mengen,
aber auch in der Softwaretechnik.
Also tatsächlich einfach beim Programmieren braucht man sie ziemlich oft.
Ich habe hier auf der Folie mal so ein bisschen angedeutet,
was so der fundamentale Unterschied ist.
Das eine soll so eine Hänge sein, dass das hier so
ein bisschen wolkig angedeutet und das andere soll eine Liste sein.
Bei einer Liste ist es so, es gibt irgendwie eine Ordnung.
Das heißt also, die Dinge haben eine Reihenfolge,
während man bei so einer Menge eigentlich nicht davon ausgeht,
dass da irgendwie eine Reihenfolge vorhanden ist.
Ungeordnet. Und in einer Menge sind auch üblicherweise die Elemente nur einmal vorhanden,
während man hier zum Beispiel in dieser Liste sieht,
dass dieses komische blaue Dreieck hier doppelt in dieser Liste vorhanden ist und auch diese Figur,
diese gelbliche Figur ist zweimal in dieser Liste vorhanden.
Das heißt, in einer Liste können durchaus Duplikate vorkommen.
Das sind erstmal so, das ist erstmal die Übersicht,
worüber wir jetzt erstmal
ein bisschen konkreter reden
Das kann man sehr unterschiedlich machen. Also Listen kann man
sehr theoretisch angehen. Es gibt ja diese mathematischen Ansätze,
auch eine theoretische Informatik. Da ist es oft so,
dass man eine rekursive Definition wählt. Sagt man einfach,
eine Liste ist entweder eine leere Liste oder ein einzelnes Element mit einer Liste dahinter.
Das kann man so sehen. Und das ist, wie gesagt,
in der theoretischen Informatik, auch in der funktionalen Programmierung sehr ausgeprägt.
Wir haben hier ein eher pragmatisches Verhältnis zu Listen.
Und wir kommen vor allen Dingen über den Umgang mit einer Liste.
Und wir wollen auch tatsächlich explizit darüber reden, dass diese
Elemente in einer Liste eine Position haben. Also eine explizite Position. Das heißt,
wenn ich sowas habe, wie eine Liste von Strings,
sie soll jetzt hier so aufgebaut sein von links nach rechts,
also das nullte oder erste Element ist Peter,
dann kommt Paul, dann kommt Mary,
dann Peter und dann Jan. Nehmen wir mal an,
das ist jetzt eine Liste von Strings,
um in einer Schule eine Pausenaufsicht einzuteilen.
Das heißt also, Peter ist das erste dran,
dann Paul, dann Mary und so weiter.
Da kann man jetzt erstmal sich klar machen,
diese Elemente in der Liste haben einen Index und in der Informatik wisst ihr inzwischen auch,
fangen wir gerne an, bei null zu zählen.
Das heißt, das nullte Element oder das erste Element hat den Index null,
nämlich hier Peter, dann Paul 1 und so weiter.
Was wichtig ist, wenn man mit einer Liste umgeht,
ist, dass sie sich verändern kann.
Das heißt, ich kann jetzt mich dafür entscheiden,
zu sagen, ich möchte jetzt die Reihenfolge etwas ändern.
Ich möchte jetzt zum Beispiel an zweiter Position,
möchte ich jetzt jemanden einschieben,
also zum Beispiel Jan soll jetzt diese Wenn Peter gerade die aktuelle Pause beaufsichtigt,
dann wird Jan die nächste machen.
Jetzt haben sich die Indizis verschoben, ganz banal.
Es ist wirklich keine Hexenkunst, die wir uns jetzt hier angucken.
Aber man muss sich klarmachen, dass Paul,
Mary und Peter und Jan, dass die alle jetzt einen anderen Index haben,
als sie vorher hatten in der Liste.
Wenn es dieselbe Liste ist, wenn wir diese Idee haben,
eine Liste kann ihren, ihre Belegung ändern.
Man kann in der Liste die Elemente einfügen oder entfernen.
Und genauso kann ich natürlich auch hier jetzt tatsächlich ein Element entfernen.
Das heißt, den zweiten Eintracht für Peter möchte ich entfernen.
Wie mache ich das? Ich streiche den da einfach raus
. So, und dann sieht das irgendwie so aus.
Und dann hat man wieder andere Indizes
Das ist, wie gesagt, erstmal nur,
um sich klarzumachen, wie eine Liste funktioniert.
Das ist einfach eine Menge, ist, wenn man sie
theoretisch betrachtet, erstmal eine Sammlung von gleichartigen Elementen.
Und bei einer Menge ganz wichtiges Konzept, die Elemente,
die da drin sind, dürfen nur einmal vorkommen.
Es gibt auch eine andere Sichtaufmengen, das sind dann Multimengen oder mehrfach Mengen.
Da kann tatsächlich ein Element auch mehrfach vorkommen.
Wir betrachten jetzt einfach erstmal das einfache Konzept von Mengen,
in denen ein Element nur einmal vorkommen darf.
Dann gibt es so Operationen auf diesen Mengen. Das heißt,
man kann ein Element einfügen, Insert, Delete,
ein Element entfernen, man kann fragen,
ob ein Element enthalten ist
Und dann kann man sich auch vorstellen,
dass es sowas gibt wie Mengen theoretische Verknüpfungen. Das heißt,
ich kann die Vereinigungsmenge bilden, die Schnittmenge und ähnliches.
Das sind alles Dinge, die aus der Mathematik vermutlich gut kennt.
Auch hier interessiert uns primär so, was macht man denn mit so einer Menge?
Wie ist denn der Umgang mit einer Menge?
Und da habe ich ein bisschen konkreteres Beispiel hier immer vorbereitet.
Und zwar, wenn man sich jetzt mal hier sowas anguckt,
mal wieder, ich gehe mal auf die Webseite vom Spiegel
Und hier sind jetzt irgendwelche Artikel, ihr kennt das,
jetzt kann man hier irgendwo draufklicken und sagen,
ich möchte mehr lesen zu diesem Text hier,
irgendwie Stuttgart 21, wird doch nochmal teurer.
Überraschung. So, und jetzt kann ich hier ja
diesen Text hernehmen und als eine Liste von Wörtern betrachten.
Ich kann also sagen, hier in dieser Liste von,
dieser Text ist eine Liste von Wörtern,
dieses das erste Wort,
dieses das zweite Wort,
dieses ist das dritte Wort und so weiter
Das ist, glaube ich, relativ gut verständlich. Das heißt,
ich könnte jetzt einfach diesen Text hier runterkopieren von der Webseite
in eine Datei speichern und dann könnte ich den versuchen,
in Java hier zu verarbeiten.
Das heißt, ich könnte einen längeren Text als
eine Liste von Wörtern, eine ganz wichtige Liste.
Erstens, es gibt eine Reihenfolge, ganz wichtig bei einem Text.
Welches Wort steht vorne, welche steht hinten, ganz wichtig.
Und es können natürlich auch Wörter mehrfach vorkommen, logisch.
In jedem Text, den wir schreiben, kommen bestimmte Wörter
mehrfach vor. Wir können aber auch,
und das ist jetzt sozusagen der Punkt,
wo man dann so ein bisschen die Unterschiede zwischen Mengen und Listen
nochmal ein bisschen klarer kriegt,
wir können den auch als eine Menge von Wörtern betrachten
Das heißt, wenn mich primär interessiert, welche Wörter kommen in einem Text vor,
dann ist das was anderes. Dann versuche ich sozusagen,
diese Liste abzubilden auf eine Menge und zu sagen, naja,
ich möchte wirklich nur wissen, was ist der Korpus dieses Textes.
Also welcher Wortschatz kommt da zum Einsatz?
Wie viele verschiedene Wörter gibt es denn da? So,
wenn wir sowas erst mal uns theoretisch vorstellen können, klar,
dann kann ich für mehrere Texte solche Mengen bilden, sozusagen den Korpus von verschiedenen Texten.
Und dann kann ich fragen, naja, was ist denn,
wenn ich Wörter sowohl in Text 1 als auch in Text 2 habe?
Also wir nehmen mal an,
wir haben hier irgendwie so einen Text über Kapitalmärkte,
Renditechancen, Shareholder oder Value, was weiß ich,
das ist irgendwie wahrscheinlich ein Text, den ich hier,
den habe ich ja tatsächlich am Dateisystem, über die Finanzkrise vor ein paar Jahren.
Dann gibt es hier was, vielleicht einen Text über irgendwas Biologisches,
Nacht aktiv, Wurfgröße, Maulwürfe, keine Ahnung,
und irgendwas über Architektur.
Ja, und jetzt kann ich ja als erstes mal gucken,
welche Texte sind denn sowohl in Text 1 als auch in Text 2 enthalten?
Also was ist die Schnittmenge der Wörter in diesen Texten?
Das sind vermutlich Füllwörter, also und oder ist und sowas.
Das ist vermutlich wenig sinntragend. Und dann wird es spannender,
wenn ich dann mir überlege, dass ich ja vielleicht
diese Füllwörter von den eigentlichen Wörtern des Textes abziehen kann.
Also von dem Korpus eines Textes ziehe ich Füllwörter ab
und kriege dann wahrscheinlich wenige Wörter,
die aber extrem sinntragend sind,
weil sie spezifisch für diesen Text sind
Ich weiß nicht, ob die Idee so ganz klar ist.
Ich kann es aber auch nochmal live zeigen,
weil ich habe natürlich ein Projekt dafür in BlueJ. Ich mache mal Guestmar Object zu.
Das sieht so aus. Ich habe eine klasse Worteinleser und
eine klasse Texteinleser. Die klasse Worteinleser sieht erstmal sehr einfach
aus von der Schnittstelle her. Ich übergebe als Parameter einen Dateinamen,
das heißt im Dateisystem ist es tatsächlich so,
ich habe hier dieses Projekt liegen und dann habe ich hier irgendwelche Texte.
Analyse, langer Text, Buttenberg,
der lange Text ist irgendwie so ein ganz,
dass der über die Finanzkrise hier
Und dann habe ich hier einen Text über den Regenwald.
Das ist irgendwie auch ein Text, der hier verarbeitet wird.
Und da gibt es hier irgendwie so einen Analyse-Text,
aber das ist wieder der Regenwald-Text.
Also der Analyse-Text, den ich gleich analysieren will. Gut,
also ich habe einen langen Text über die Finanzkrise und einen Analyse-Text über,
also habe ich irgendwie aus Spiegel rausgeguckt, den Spiegel Online rauskopiert.
Und jetzt kann ich tatsächlich hier bei diesem Worteinleser,
da sage ich einfach, jetzt gebe ich einen Dateinamen an,
also eine von diesen Dateien.
Und ich übergebe eine Liste. Jaba You Till List,
eine Liste von Strings. Ich gebe also einen leeren Behälter
rein und sage, fülle mir den mal mit den Wörtern
aus der Datei
Und am Ende habe ich dann tatsächlich eine Liste von Wörtern.
Wir können uns das mal angucken,
wie das in der Implementierung aussieht,
dass hier schon mal so ein Eindruck bekommt,
wie man so Listen ganz gut benutzen kann.
Also hier stringen, Lateinahme, das ist der Parameter.
Und es wird hier die Wortliste übergeben, also eine leere Wortliste üblicherweise.
Wobei man nicht weiß, was hier übergeben wird.
Wir werden es aber gleich so benutzen. Dann ist hier
so ein bisschen Code, den müsst ihr nicht verstehen.
Hier wird irgendwie jetzt aus einer Datei eingelesen.
Das ist so ein bisschen Zauberei in Java,
muss man sich jetzt nicht so angucken.
Aber hier gibt es einen Aufruf, wenn denn,
es wird also zahlenweise eingelesen,
verarbeitet Zeile
Hier wird also diese Zeile irgendwie, die da eingelesen wurde, übergeben.
Und die Wortliste wird auch übergeben. Also diese Wortliste,
die übergeben wurde. Und dann haben wir hier diese verarbeitete Zeile.
Die verarbeitet also jede Zeile aus dieser Textdatei, indem sie die Wörter in diese Wortliste einfügt.
Man sieht hier Wortliste.at und dann ein einzelnes Wort. Wie wir das Wort kriegen,
ist so ein bisschen getrickst hier,
also erstmal mache ich hier to lower case,
die ganze Zeit wird erstmal auf Lower Case gesetzt,
dann wird hier Split aufgerufen, eine Operation bei Strings,
um hier tatsächlich an verschiedenen Stellen zu schneiden,
also an Leerstellen, verschiedenen Zeilenumbrüchen und ähnliches.
Und dann geht tatsächlich alle durch alle diese Wörter durch und
wenn das Wort länger ist als Null,
dann ersetze ich auch noch Punkte, Kommata und ähnliches.
Das ist ein Replace All, ein regulärer Ausdruck.
Also in dem String wird alles das ersetzt durch nichts.
Also die werden sozusagen alle rausgeschmissen. Das heißt, man hat,
hinterher hat man wirklich eine Menge von einer Liste, Entschuldigung,
eine Liste von Wörtern, den Text als an der Liste von Wörtern.
Okay, dieses Ding benutzen wir in dem Textvergleich.
Und was der macht, ist jetzt relativ überschaubar.
Da muss die Maus eigentlich rechts, stelle ich gerade fest.
Dann haben wir hier das Einlesen. Ich gebe wieder
den Dateinamen an
Und die Liste, in die die Wörter eingelesen werden sollen,
dann geht es hier nur darum,
dass das hier so ein bisschen ausgegeben wird,
dass man auf einer Konsole sehen kann.
Ich lese jetzt diesen Text ein und es waren so und so viele Wörter.
So, jetzt kommt der eigentliche Ablauf, den ich zeigen will.
Also erstens habe ich hier eine Liste von String deklariert.
Das ist ein langer Text. Hier deklariere ich jetzt eine,
erzeuge ich eine Arrailist, also eine Implementation des Interfaces List von String.
Dann lese ich jetzt ein, was ich hier,
rufe ich das auf, also lese den langen Text ein,
in mein,
in meine Liste von Strings,
langer Text
Und dann passiert auch was Ungewöhnliches. Ich habe hier ein Set von String,
also eine Menge von Strings, deklariere ich hier, ja.
Das ist dann der große Korpus. Damit will ich sozusagen
die Menge der Wörter in dem langen Text modellieren.
Und da erzeuge ich mir ein Hashset von String.
Das ist eine Implementation des Set-Interfaces. Set ist ein Interface und Liste
ist ein Interface, werden wir uns alles gleich noch ansehen.
Und dann übergebe ich als Konstruktorparameter hier eine Liste von Strings.
Und dann wird aus der Liste einfach durch diesen Parameter,
der hier angegeben wird, beim Erzeugen dieses neuen Sets,
werden alle Duplikate rausgeschmissen
Das heißt, aus der Liste von Strings wird mit einem Schlag,
wird eine Menge von Strings, wo wirklich dann jedes Wort nur noch einmal vorkommt.
Und dann kann ich eben halt genau die Frage beantworten,
dann habe ich ja in dieser Variablen großer Korpus eine Menge von Strings,
habe ich dann, kann ich das Size aufrufen,
zum Beispiel, um fragen, ja,
wie viele Wörter sind die jetzt drin?
Also wie viele verschiedene Wörter sind in dem langen Text drin?
So, wenn ich das jetzt einfach mal ausführe,
dann sieht man hier, kommt das dabei raus,
es sind, der lange Text hat 20.457 Wörter,
ein relativ langer Text.
Und davon sind aber nur 5.253 verschieden
Also mehrere, manche Wörter kamen halt mehrfach vor,
klar, kann man sich ganz gut vorstellen. So,
und jetzt kommt der nächste Schritt, jetzt nehme ich die,
den etwas kleineren Text, ja, das ist der Detext,
den ich analysieren will. Die Idee ist,
wenn ich von einem kleinen Text alle Wörter abziehe,
die in einem großen Text sind,
dann werden vermutlich die ganzen Füllwörter aus dem zu analysierenden Text rausgezogen,
es bleiben diese signifikanten Wörter über, da will ich hin,
komm mit dieser kleinen Show hier.
Also habe ich hier den Analyse-Text, wieder eine Liste von Strings,
da lasse ich mir jetzt diesen Analyse-Text einlesen,
also diesen Regenwaldtext in diesem Fall
Und ich mache es wieder genauso, mache mir auch eine Menge.
Also an Analyse Korpus. Wie viele verschiedene Wörter sind das denn?
Und dann wird mir das hier auch ausgegeben. So,
das ist noch überschaubar, das haben wir schon gesehen,
das ist jetzt keine Hexenkunst, brauche ich nicht gleich direkt vorführen.
Hier kommt der nächste Abschnitt, jetzt bilde ich die Schnittmenge.
Eine Menge von Wörtern, von Strings, Schnittmenge,
soll hier sein, wieder ein Hashset.
Und ich gebe erst mal als Konstruktorparameter den großen Korpus rein.
Und dann rufe ich auf Schnittmenge retain all. Das ist eine Operation,
um zu sagen, hallo, Schnittmenge, behalte,
da sind jetzt alle Wörter des großen Textes drin,
behalte mal alle Wörter, die auch in dem Analyse-Korpus drin sind.
Retain all, was auch im Analyse-Korpus drin ist.
Und dann wird hier die Schnittmenge irgendwie ausgegeben,
wie viele Wörter da drin sind.
Okay. Und dann zum Schluss hier dieser kleine Abschnitt,
die relevanten Wörter. Jetzt sage ich hier das Gleiche wieder.
Ich habe den Analyse-Korpus. Und ich entferne alle Wörter aus
dem großen Korpus. Ich habe also eine Menge von,
eine kleine Menge von Wörtern und entferne alle Wörter,
die in dem anderen Text drin sind,
in dem großen Text drin sind.
Und dann kriege ich hier sozusagen relevante Wörter,
nämlich kurzer Text minus langer Text,
wie viele relevante Wörter stecken denn da drin
So, dann habe ich hier noch ein bisschen mehr gezaubert.
Das müsst ihr euch nicht unbedingt angucken,
aber ich kann es zumindest mal in der Ausführung dann zeigen.
Ich habe nämlich dann mir die Häufigkeiten berechnen lassen.
Also tatsächlich das Auftreten, wie häufig die Wörter vorkommen.
Da kriege ich also eine Abbildung von einem Map, einer Abbildung.
Das habe ich hier auf der nächsten Folie auch schon mal
so ein bisschen beschrieben, was eine Map ist.
Das ist eine weitere wichtige Menge, eine weitere wichtige Sammlungstyp
in Java und allgemein auch konzeptuell für die Programmierung.
Das ist eine Menge von Schlüsselwertpaaren. Das heißt,
ich habe immer einen Schlüssel und bilde den ab auf
einen Wert
In diesem Beispiel hier möchte ich abbilden von einem Wort auf die Anzahl seiner Häufigkeit.
Also für jedes Wort möchte ich einfach festhalten, wie häufig es vorkommt.
Und dann möchte ich dann mir letztendlich ausgeben lassen, so eine kompakte Darstellung.
Das gucken wir uns jetzt im Detail nicht an,
aber auch hier dann einfach eine Abbildung von Wörtern auf ihre Häufigkeiten,
ist eine Abbildung von String auf Intager und eine Abbildung von Häufigkeiten,
von Häufigkeiten,
auf Mengen der Wörter mit der jeweiligen Häufigkeit Intager auf Set-Out-String.
Ich zeige mal, was da jetzt rauskommt,
das ist jetzt möglicherweise ein bisschen viel,
das jetzt alles nachzuvollziehen, kann ja auch keiner jetzt erwarten.
Aber ich will einfach mal zeigen, was da rauskommt,
dass das irgendwie ganz spannende Ergebnisse liefern kann.
So, also, wir haben jetzt hier gesehen,
es sind 384 verschiedene Wörter, in denen zu analysieren den Text.
Also, es war ein relativ kurzer Text, 6664 Wörter.
Da fahren 384 verschieden. Die Schnittmenge beider Texte,
also die Füllwörter, in Anführungsstrichen, waren 207.
Wenn ich die jetzt abgezogen habe von dem kurzen Text,
dann blieben noch 177 Wörter über.
Also, immerhin, wir sind schon von 664
auf 177 gekommen
Wahrscheinlich ziemlich relevant, diese Wörter. Und dann habe ich hier,
wie gesagt, mir dann ausgeben lassen, welche am häufigsten vorkommen.
Und also nur die, die mehr als einmal vorkommen.
Und dann sieht man hier so Quitto, Kohlendioxid, erspart Indianerstämme,
equadorisch, äquadorianische, dann Atmosphäre, Äquador, Erdöl,
Öl, also offensichtlich geht es in diesem Artikel um Öl.
Und darüber, dass es möglicherweise beim Regenwald ganz günstig ist,
da was abzuholzen, um irgendwie noch mehr Erdöl gewinnen zu können oder ähnliches.
Das einfach nur, um zu zeigen,
mit Mengen und Listen kann man ziemlich spannende Sachen machen auf Texten.
Okay, das war jetzt dieses kleine Beispiel
Was ihr jetzt schon gesehen habt, ist,
während wir objektorientiert Sammlungen betrachten, also Listen und Mengen insbesondere,
dann sind die eher zustandsbasiert.
Das heißt, wir können ein Exemplar einer Menge oder
einer Liste erzeugen und dann da einfach Dinge reintun,
dadurch ändern die ihren Zustand, ihre Belegung.
Ganz allgemein hier im Umfeld von Java werden,
wenn wir über Sammlungen sprechen werden, sprechen wir über Collections.
Eine Sammlung ist ein Objekt, das eine Gruppe von
anderen Objekten zusammenfasst
Ganz einfach. Sammlung werden verwendet, um andere Objekte zu speichern,
gemeinsam zu manipulieren und Mengen von Objekten an andere weiterzugeben.
Also ich möchte als Parameter eine Menge übergeben,
haben wir gerade gesehen, kann man sehr schön machen.
Was ziemlich häufig der Fall ist, dass die Sammlung
Objekte vom selben Typ enthalten. Eine Menge von Briefen,
eine Menge von Konten, eine Liste von Personen, ähnliches.
Und wir bräuchten nichte Begriffe für Sammlungen, sind auch Behälter oder Container.
Also gerade wenn man so eine zustandsbasierte Sicht hat,
dann ist das relativ angemessen. Was man hier sieht,
ist so eine Andeutung von etwas, was euch klar sein sollte inzwischen,
dass wir ja in Java alles über Referenzen machen.
Das heißt, wenn eine Sammlung Objekte enthält,
dann ist es eigentlich nicht richtig,
weil eine Sammlung kann ja nicht Objekte enthalten in Java.
Eine Sammlung kann immer nur Referenzen auf Objekte enthalten.
Das heißt, wenn das hier die Sammlung ist,
dann enthält die möglicherweise drei Referenzen auf Objekte,
die irgendwo anders im Speicher liegen.
Dann gibt es ein paar ganz zentrale Begriffe.
Das habe ich schon eben informell eingeführt hier.
Die Objekte, die in einer Sammlung gehalten werden,
die nennen wir die Elemente der Sammlung.
Keine Überraschung. Jede Sammlung sollte üblicherweise Operation bieten zum Einfügen
und entfernen von Elementen
Der Typ der enthaltenen Elemente, der Elementtyp,
wird üblicherweise auch als eine Eigenschaft der Sammlung angesehen.
Das heißt, in dem Beispiel hatten wir hier List of
String oder Set of String, also eine Menge von Zeichenketten.
Der Elementtyp gehört eigentlich tatsächlich zu einer Sammlung dazu.
Und gerade bei einer Sprache wie Java, wo wir ja auch
den Typ immer statisch festhalten wollen, gehört ja auch statisch dazu.
Dann die Anzahl der dann halt in Elemente bezeichnen wir als
ihre Kardinalität, ist einfach ein Fachbegriff.
Bei Sammlung ist diese üblicherweise nicht nach oben begrenzt.
Das ist ganz wichtig. Ein wichtiger Unterschied zu Race,
die einige von euch möglicherweise schon kennen, die kommen später,
wir werden also uns später mit Arrays beschäftigen,
weil die sehen wir als speichernahes Konnzept an,
die man ab und zu auch mal brauchen kann,
aber meistens ist es schlauer und wichtiger und angemessener,
die Sammlung des Collections Framework zu verwenden.
Die haben nämlich unter anderem den Vorteil,
dass man tatsächlich beliebig viele Elemente reinschmeißen kann.
Bei einem Array, wenn es einmal erzeugt ist,
kommen wir nächste Woche zu, habe ich nur eine bestimmte Kapazität.
Bei diesen Dingern hier, bei diesen Sammlungen in Java,
kann ich tatsächlich beliebig viele Elemente reinpacken.
In einer Liste kann ich einfach,
bis der Speicher voll ist, das ist klar,
aber konzeptuell ist das unbegrenzt
Letzte einigermaßen zentrale Begriff ist, noch wenn ein Element,
das in eine Sammlung eingefügt wird, bereits in der Sammlung enthalten ist.
Dann nennt man das einzufügende Element ein Duplikat. Keine Überraschung. So,
jetzt habe ich letzte Woche was erzählt über Interfaces und Implementationen.
Und auch jetzt können wir mit diesem Begriffswerkzeug von letzter Woche hier drauf gucken und sagen,
na gut, wir sehen bei einer Sammlung,
bei einer Menge oder bei einer Liste,
können wir unterscheiden zwischen der Schnittstelle und der Implementation.
Die Eigenschaften einer Sammlungsschnittstelle sind so Fragen wie,
wie wird mit Duplikaten umgegangen, sind die erlaubt oder nicht.
Gibt es eine Reihenfolge in der Sammlung
Und bei der Sammlungsinplementation, da kommen dann andere Fragen zum
Tragen, also wie ist diese Sammlung implementiert?
Ist das mit Arrays implementiert, mit Verkettung?
Gibt es eine Kombination dieser Konzepte? Das sehen wir uns
alles noch ausführlich an oder auch die Effizienz.
Wie effizient ist denn die Implementation? Wie schnell sind denn
die einzelnen Operationen in ihrer Ausführung? Das sehen wir uns
noch ausführlich an, aber heute konzentrieren wir uns auf die Schnittstelle.
Das heißt, wir wollen sehen als Klienten einer Sammlung,
was können wir damit machen? Welche Operationen werden mir angeboten
und wie kann ich die möglichst gewinnbringend einsetzen?
Also in erster Linie bin ich an der Schnittstelle interessiert
So, jetzt habe ich eben schon gesagt,
bei einer Sammlung kann man unterscheiden, ob es eine Reihenfolge der Elemente gibt.
Und wenn ja, wie die manipuliert ist. Wir haben
jetzt hier auf den Folien einfach drei verschiedene Möglichkeiten dargestellt.
Erstens ist es gar keine Reihenfolge definiert.
Bei Mengen üblicherweise hat man eine Reihenfolge definiert.
Die Reihenfolge ist Benutzer definiert, festlegt, festlegbar.
Das heißt, ich kann als Mensch irgendwie entscheiden,
in welcher Reihenfolge die Dinge in einer Sammlung drin sind.
Oder die Reihenfolge wird tatsächlich automatisch hergestellt.
Das heißt, die Sammlung bestimmt die Ordnung ihrer Elemente
Kann man sich vorstellen. Und dann ist die Orthogunal dazu
die Frage, wie wird mit Duplikaten umgegangen?
Sind Duplikate zugelassen? Also immer, wenn ich was hinzufüge,
wird garantiert die Kardinalität erhöht oder Duplikate sind nicht zugelassen.
Es kann sein, dass ich beim Einfügen eines Elementes ist,
sich die Kardinalität nicht ändert, weil das Element schon drin war.
So, das ist hier nochmal einfach ein bisschen systematischer in einer Tabelle dargestellt.
Das sind die möglichen Umgangsformen mit so Sammlungen. Also einfach
mal so systematisch draufgeguckt. Und wir können das einfach mal der Reihe nach durchgehen,
um einfach so ein Gefühl dafür zu kriegen,
was denn diese Eigenschaften jetzt hier bewirken.
Also nehmen wir mal hier linke obere Ecke,
Multimenge,
Da ist die Reihenfolge der Elemente irrelevant und Duplikate sind zugelassen.
Hat jemand mal irgendein Alltagsbeispiel, wo das greift,
wo man sich besser vorstellen kann,
was denn so eine Multiminge oder ein Back sein könnte, ja?
Er sagt, eine Tüte Gummibärchen, das ist ein wunderbares Beispiel.
Die Reihenfolge ist irrelevant, Duplikate sind zugelassen, also es dürfen rote,
mehrfach vorkommen und auch grüne und gelbe mehrfach vorkommen.
Gibt es noch weitere Ideen hier für sowas?
Eine Multimenge oder ein Set
, ja
Der Name, nochmal, ach so, der Name Back,
ja genau, eine Tasche, ja. Also ich habe in der Vorlesung,
im letzten Jahr hat mir jemand zugerufen,
der Inhalt der Tasche einer Frau, der Handtasche einer Frau,
da können auch Dinge doppelt drin sein, klar.
Ich habe hier noch so ein paar Beispiele mitgebracht,
ein Scrabble-Beutel, wenn ihr Scrabble spielt, dann wisst ihr,
da gibt es diesen Beutel mit den Buchstaben drin und die
Buchstaben sind einfach mehrfach drin und die Reihenfolge spielt aber keine Rolle,
die sind also irgendwie da drin.
Oder Münzen in einer Geldbörse,
wenn ihr drei ein Euro-Stück habt in eurem Portemonnaie,
dann ist euch wurscht, welches ihr dann nehmt.
Das ist einfach nur wichtig,
dass es überhaupt drin ist
Ihr irgendwas bezahlen müsst. Bei der Liste, was sind
mal konkrete Beispiele für Listen? Also, Reihenfolge benutzert,
ich finde also, als Mensch lege ich fest,
in welcher Reihenfolge da was drin ist und Duplikate sind zugelassen.
Was fällt euch da sofort ein? Ja. Bitte?
Eine Redeliste. Ja, es kann durchaus sein,
dass bei einem Symposium manche Personen mehrfach einen Vortrag halten,
also sind Duplikate zugelassen und die Reihenfolge ist definitiv benutzerdefinitiv.
Also irgendjemand legt die Reihenfolge ja fest
Wenn du das gemeint hast, ich hoffe, du hast die Rednerliste gemeint,
aber hier ist auch noch was anderes eine Playlist.
Wenn ihr iTunes benutzt oder ähnliche Software, um Musik
zu verwalten in einer Playlist, können Titel mehrfach vorkommen.
Aber die Reihenfolge lege ich üblicherweise selber fest. Ich möchte gerne
tatsächlich genau festlegen, in welcher Reihenfolge Dinge da abgespielt werden.
Oder ans Gravel-Wort, in einem Scrabble-Wort, kann ein Buchstabe
mehrfach vorkommen, aber die Reihenfolge ist doch ziemlich Benutzer definiert.
Also irgendjemand legt ja dann fest, was die Semantik
des Wortes ist und wie es denn genau heißt.
Reihenfolge automatisch und Duplikate zugelassen, also so eine sortierte Liste
Er hat mal eine Idee, wo man
sowas gebrauchen könnte oder wo sowas irgendwie im Alltagsgebrauch vorkommt.
Das ist nicht ganz so einfach. Da kommen selten irgendwie
so die Namensliste von Fallen. Eine Namensliste von Teilnehmern.
Nur die Vornamen, meinst du? Ah, okay.
Da sind Duplikate zugelassen. Aber die Reihenfolge automatisch,
du meinst, wenn sie sortiert ist, nach Vornamen sortiert.
Ja, könnte man, könnte man haben.
Stimmt. Das ist ein Beispiel. Noch weitere anschauliche Beispiele
für sortierte Listen,
Er zeigt den Namen. Okay, er sagt eine Anmeldeliste,
wo die sortiert ist nach Anmeldezeitpunkt.
Da kann auch derselbe Name vorkam. Ich habe sowas ähnliches hier.
Messwerte. Da ist noch ein Vorschlag. Ein Tagebuch?
Ein Tagebuch. Oha, das ist aber dann ein Eintrag im Tagebuch.
Und da gibt es dann Duplikate. Reihenfolge automatisch auf jeden Fall,
weil man tatsächlich immer das natürlich zeitlich geordnet ablegt.
Und Duplikate, klar, manchmal schreibt man dasselbe rein.
Da schreibt man denen, heute ist nichts passiert.
Wenn man das mehrfach hinschreibt, dann hat man schon Duplikate.
Ja, okay, ich habe hier jetzt Messwerte,
wo man davon ausgeht, dass bestimmte Messwerte in einer Wetterstation
zum Beispiel aufgenommen werden und immer in 5-Sekunden-Takt oder 5-Minuten-Takt aufgezeigt wird.
Das heißt, die Reihenfolge ist auch komplett automatisch festgelegt.
Durch die Reihenfolge der Erfassung und dann sind natürlich auch Duplikate
drin, weil dieselbe Temperatur kann mehrfach gemessen werden.
Okay, Mengen, Duplikate zugelassen, Duplikate nicht zugreifen,
Entschuldigung, Duplikate nicht zugelassen, Reihenfolge irrelevant.
Wir haben jetzt schon gesagt, Mengen und Listen sind so die besten Beispiele,
hatten die bei uns jetzt einen Vorschlag für eine Menge.
Nochmal was, was kommt euch da so in den Sinn?
Haben wir eben schon gesehen, der Korpus eines Textes,
also welche verschiedenen Wörter sind in einem Text drin.
Ich habe hier noch sowas wie Babynamen
Wenn jemand irgendwie Eltern wird, älter,
und dann irgendwie drüber nachdenkt, wie das Kind denn heißen soll,
dann wird man üblicherweise auch so Namen zusammenschmeißen in einen Topf
und dann will man natürlich erstmal nur sammeln für ein Brainstorming.
So, Reihenfolgebenutzer definiert, Duplikate nicht zugelassen. Puh,
was ist das denn? Wir hatten mal eine Idee,
wofür man sowas gebrauchen könnte, in welchem Kontext?
Irgendeine, ja
Er sagt, eine gewichtete Menge,
in der man den Elementen verschiedene Gewichte zuordnet, ja,
also die Gewichte, das hört sich eher so danach an,
dass dann hier so eine automatische Sortierung stattfindet.
Hier ist es so, die Reihenfolge ist Benutzer definiert.
Ich habe hier, glaube ich, ein Beispiel,
ein Wunschzettel, tolles Beispiel. Also Duplikate, also auf
dem Wunschzettel schreibt man ja üblicherweise nicht alles mehrfach hin.
Und das ist meistens auch Benutzer definiert. Das heißt,
irgendwie schreibe ich ganz nach oben, was mir ganz wichtig ist,
ja, also habe ich jedenfalls früher so gemacht,
als ich nach Wunschzettel geschrieben habe.
Oder auch Bilder in einer Galerie, sehr schönes Beispiel,
ja, wenn du in einer Kunstausstellung geht,
dann werden da hoffentlich keine Duplikate hängen.
Also es wird nicht ein Bild an mehrfach hängen
Aber die Reihenfolge ist komplett benutzter Definition. Also irgendein Mensch,
ein Kurator oder wer auch immer, hat sich überlegt,
aha, in der Reihenfolge sollten die Dinger da ausgestellt sein.
Und Reihenfolge automatisch publikat nicht zugelassen, habe ich hier die Bundesliga-Tabelle.
Das ist so ein Beispiel, wo man dann sagen kann,
da ist eine Gewichtung. Das heißt,
die Mannschaften können Punkte sammeln und die Reihenfolge ist berechenbar.
Also es gibt irgendwie eine Möglichkeit, das automatisch zu berechnen,
die Reihenfolge, während hier der Mensch die Reihenfolge bestimmt.
Okay, das ist nur einfach,
dass sie mal so einen Überblick habt,
dass diese Umgangsform mit Duplikaten und Nicht-Duplikaten und verschiedene Arten Reihenfolgen
zu definieren durchaus unterschiedliche Effekte haben können
So, jetzt ist es so, im Java Collections Framework,
da gibt es ganz viel Unterstützung für Sammlung.
Wir haben jetzt eben schon live so ein bisschen Code gesehen.
Das Framework besteht aus einer Reihe von Interfaces und einer Reihe von Klassen,
die diese Interfaces implementieren. Das heißt, es war ganz nützlich,
dass wir die Interfaces in der letzten Woche kennengelernt haben,
weil wenn man die kennt,
kann man das Collections Framework schon mal ganz gut verstehen.
Das heißt, es gibt eine Reihe von Interfaces und
eine Reihe von Klassen. Dieses Framework ist sehr etabliert,
also es kann quasi schon als ein Teil der Sprache angesehen werden,
obwohl es tatsächlich nicht spezial behandelt ist.
Ihr erinnert euch, String Java spezial behandelt. Gab es syntaktische Unterstützung,
die Literale sind spezial hervorgehoben und man kann mit Plus Strings konkatinieren.
Das ist Spezialbehandlung, das gibt es hier bei den Collections Framework nicht.
Trotzdem ist es wirklich inzwischen so quasi ein Bestandteil der Sprache.
Okay, und jetzt wollen wir uns die beiden Interfaces List und Set genauer ansehen.
Also wir haben ja die schon irgendwie informell eben in dem
Anwendungsbeispiel gesehen, wie sie eingesetzt werden.
Das heißt, wir gehen erstmal in die Interfaces ran,
weil die definieren ja den Umgang, die sagen ja,
was kann man denn damit machen?
Bevor ich jetzt aber auf die einzelnen Interfaces angehe,
bin ich noch mal ein bisschen was Allgemeineres sagen,
nämlich über das sogenannte Java API, Application Programming Interface,
API steht für Application Programme oder Programming Interface.
Das sind alle, die Klassen und Interfaces von Java,
die mitgeliefert werden. Also wenn ihr irgendwo eine Java-Installation habt,
dann kommen da unheimlich viele Sachen mit dazu,
die man erstmal gar nicht unbedingt braucht.
Das ist ziemlich viel Zeug. Also wenn ihr
so eine Java-7-Installation habt, dann sind das
mehrere tausend Klassen
Damit das ein bisschen besser strukturiert ist, haben die Leute,
die das entworfen haben, das Ganze zergliedert in kleinere,
handhabbare Happen in sogenannte Pakete oder Englisch Packages.
Es gibt ein ganz zentrales Paket in Java,
das heißt Java Lang. Java punktlang. Und das enthält
alle Klasseninterfaces, die als Teil der Sprache angesehen werden.
Also tatsächlich alles, was immer sichtbar ist,
egal in welchem Java-Programm ihr euch bewegt,
das sind genau die Klassen, die immer vorhanden sind.
Da muss man auch nichts tun,
um sie irgendwie zu benutzen zu können, die sind einfach immer da.
Also String gehört da zum Beispiel
auch dazu
Klassen- und Interfaces aus allen anderen Paketen muss man üblicherweise importieren,
um sie direkt benutzen zu können.
Ich sage jetzt, um sie direkt benutzen zu können,
dass Java-Collections-Framework beispielsweise liegt im Paket Java Youtil.
Das sieht man jetzt, wenn man hier das Beispiel mal anguckt.
Ich habe ja hier diesen Textvergleicher. Dann sieht man ganz
oben genau diese Imports. Also ich habe hier geschrieben,
Import, Java Youtillist, im Port Java Youtill Arraylist.
Das eine ist das Interface, das sind die Interfaces,
List, Set on Map.
Und das sind die Implementationen dazu. Arraylist ist eine Implementation
des Interfaces List,
aber nur eine
Hashtag ist eine Implementation des Interfaces Set und Hashmap ist eine Implementation des Interfaces Map.
Und die importiere ich hier und deswegen kann ich hier
an verschiedenen Stellen auch wirklich einfach diesen Namen unqualifiziert benutzen.
Wenn ich das jetzt weglassen würde, nehmen wir mal an,
ich würde hier an dieser Stelle diesen Import einfach auskommentieren,
dann lässt sich das nicht mehr übersetzen.
Dann sagt er nämlich, cannot find sümble, class list.
Hier steht List. Ich habe das durch den Import,
aber allerdings nur erreicht, dass sich das hier nicht vollqualifiziert angeben muss.
Ich kann es aber vollqualifiziert angehen.
Das heißt, ich kann einfach den Paketnamen angeben.
Java,
you till list
Jetzt lässt sich das an dieser Stelle übersetzen. Jetzt habe ich hier noch
eine weitere Stelle, an der auch nur List auftritt.
Ich kann also jetzt an allen Stellen,
an denen das steht, Java, You Till List schreiben.
Dann gibt es noch eine Stelle und so weiter.
Ich könnte die jetzt alle ersetzen. Das heißt,
dieses Importieren ist nur eine Möglichkeit, den Namen zu verkürzen,
statt an allen Stellen den vollqualifizierten Namen anzugeben,
kann ich einfach jetzt einfach nur einmal sagen,
ich importiere List und dann kann ich das in diesem,
in dieser Klasse, hier, in dieser Klassendefinition unqualifiziert benutzen.
Das sind diese Importanweisungen, Kann man schreiben, muss man aber nicht.
Einfach, dass wir etwas klar ist. Es heißt nicht,
dass man diese Klassen nicht benutzen kann, wenn man sie nicht importiert.
Dass es einfach nur um die kurzen Namen verwenden zu können.
Okay, und dass da war API,
also dieses Application Programm Interface im Java-Doc-Format, das sieht so aus.
Das habt ihr auch schon ein bisschen gesehen,
als euch die Schnittstelle der Klassen String angesehen hat.
Bevor ich das jetzt hier mal live zeige,
will ich nur auch noch mal hier darauf hinweisen.
Also hier zum Beispiel, links oben,
da sind alle Pakete aufgeführt, die zur Java API gehören.
Das ist jetzt hier zum Beispiel für Java 5 und das hier
Wenn man es genau nimmt, ist das eigentlich keine Liste.
Weil erstens hat man keine Duplikate drin, die Paketennamen müssen eindeutig sein.
Und zweitens ist es hier alphabetisch sortiert. Also es ist
wahrscheinlich eine automatisch sortierte Menge. So, das können wir
uns mal angucken. Ich habe hier den Link dazu.
Hier ist es live, die Java 5 API.
Also hier sieht man ganz viele Pakete. Das ist wirklich
viel Zeug. Ihr seht, das ist ganz schön viel Zeug.
Und dann gibt es hier unter anderem Java Leng.
Mal gucken, es müsste hier
irgendwo sein
Java Lenken. In Java Leng sind alle Dinge drin,
die zur Sprache dazugehören. Da sind unter anderem drin,
Object ist da drin, kommen wir heute noch drauf.
Hier sind auch die Rapperklassen, Integer und so weiter,
wählen wir uns heute auch noch an.
Was wir hier auf alle Fälle finden, ist String.
String ist eine relativ wichtige Klasse, haben wir ja auch schon kennengelernt.
Okay, und dann gibt es aber auch ein Paket,
Java YouTill, das ist hier.
Und da drin sind jetzt, aha,
mehrere Interfaces, also zum Beispiel List,
hier ist das Interface List oder das Interface Set
Und dann ist hier jeweils beschrieben, was denn da so
an Eigenschaften definiert ist. Und es sind die ganzen Methoden
definiert, die schauen wir uns gleich etwas genauer an.
Aber das machen wir, glaube ich,
jetzt ganz gut, passt es, nach der Pause.
Es sei denn, es sind jetzt noch Fragen zu dem,
was ich bis jetzt erzählt habe.
Da ist eine Frage. Ja, das heißt,
wenn ich gesprochen habe, kann ich sagen, mit dem Partner wieder.
Ja, identischer Objekt. Also die gleiche, die zweite
Präferenz ist noch das Gleiche. Oder es ist ein Gesundheitsobjekt,
ein Gefall, das sich vielleicht verhalten,
weil wir nicht ganz so probieren in der Vorstellung,
Für mich war es eine schöne Objekte quasi, die Reale aufnehmen.
Okay, also die Frage, die ihr stellt, ist,
wie ist das mit den Duplikaten? Ich habe gesagt,
es gibt so Mengen, es gibt so Sammlungen,
da spielen Duplikat in der Rolle, bei Mengen zum Beispiel.
Und wie wird jetzt Duplikat definiert?
Wird das über die Identität definiert oder über die Gleichheit?
Also es sind einfach zwei verschiedene Objekte, sind ja immer verschieden.
Oder reicht das, wenn sie gleich sind? Und genau auf
diese Frage gehen wir nach der Pause nochmal ausführlich ein.
Da wird noch ein bisschen mehr dazu kommen. Das ist
ein ganz, ganz wichtiger Punkt. Wie wird denn entschieden,
ob etwas in einer Menge als Duplikat angesehen wird?
Das werden wir uns gleich noch angesehen
Sonst noch Fragen zu dem, was ich bis jetzt gesagt habe.
Okay, dann machen wir fünf Minuten Pause.
Dann würde ich sagen, die fünf Minuten sind um.
Falls ihr schon ganz ungeduldig seid, dass wir auch nochmal
eine Storesi-Umfrage machen, es gibt heute noch eine zum Ende.
Also da werde ich nochmal wieder ein paar Fragen stellen.
Gut, also wir wollen uns jetzt ein bisschen konkreter ansehen,
was wir bisher so als Ahnung haben,
wie so Listen und Mengen in Java funktionieren
Wir sind uns zuerst das Interface-Set an. Also tatsächlich die Modellierung
einer Menge in Java Collection Framework. Hier ist so ein Ausschnitt,
so mit den wichtigsten Elementen, die wir brauchen.
Also es gibt dieses Interface-Set. Und was man hier als erstes sehen muss,
ist, dass bei einem, bei diesen ganzen Collections-Framework-Typen,
also sowohl Interface als auch bei den Klassen,
gibt es diese eigenartigen Spitzenpfeile hier.
Diese spitzen Klammern, die dieses hier in diesem Fall
ein E umschließen
Damit wird hier ein Platzhalter definiert für den Element-Typ. Das heißt,
wir haben das eben im Beispiel schon gesehen, in diesem Textvergleicher,
da habe ich hier zum Beispiel ein Set of String deklariert,
relevante Wörter.
Meine Variable heißt relevante Wörter. Der Typ ist Set of String.
Und in dieser Dokumentation ist jetzt der Typ der Elemente hier als Platzhalter beschrieben als E.
Weil ich kann ja ein Set of String haben,
ich kann ein Set auf Konto haben,
ich kann ein Set of Person haben,
was immer.
Das ist ja
das Collections Framework ist allgemeingültig
Damit Sammlungen modellieren können von beliebigen Elementtypen. Und hier ist
sozusagen das als Platzhalter formuliert. Und deswegen ist es
auch so, dass dieser Platzhalter dann irgendwo auftauscht.
Zum Beispiel bei der Operation Ad hier, Ad,
da steht dieser Parameter E als formaler Parameter.
Das heißt, wenn ich ein Set of String habe,
dann kann ich mit der Operation Ad auch nur einen String einfügen.
Da wird also tatsächlich statisch vom Compiler geprüft,
ob das auch vom Typ her dazu passt.
Also das ist dann generisch definiert. Das ist so der
Begriff für solche Platzhalter, für solche Typen mit solchen Platzhaltern
Okay, wir haben hier dann Operationen,
die man ganz gut gebrauchen kann, zum Beispiel Size,
Size liefert mir, wie viele Elemente sind wirklich in der Sammlung drin.
Dann gibt es so eine Convenience-Methode, ist Empty.
Ich kann natürlich auch fragen, ist Size gleich gleich null?
Dann ist das das Gleiche, wie ist Empty,
aber die haben trotzdem eine Operation, ist Empty mit angeboten.
Dann ein Contains. Ich kann tatsächlich also sagen, ist ein
bestimmtes Objekt enthalten. Was man hier sieht, ist,
dass hier der Parametertyp Object ist. Das heißt tatsächlich,
an dieser Stelle kann ich ein beliebiges Objekt reinstecken und eine
Menge von Strings zum Beispiel fragen, ob ein Konto da drin ist.
Ist ein bisschen sinnlos, aber das geht leider.
Das ist noch so ein Erbstück aus den alten Tagen,
als das Collections-Framework noch nicht generisch war.
Da oben in der Ecke habe ich ein bisschen das Problem,
dass da einige Leute, glaube ich, gestört sind, wenn ihr dazu laut rumalbert.
Wäre nett, wenn ihr euch ein bisschen zurücknehmen könnt, danke. Gut,
also es gibt Operationen, die noch mit Object definiert sind,
das ist sozusagen so ein Erbstücke aus alten Java-Zeiten,
aber schlauerweise ist es meist so,
dass man sowas wie hier hat, also bei Ed,
das tatsächlich klar ist, wenn es eine Menge von Strings ist,
dass dann auch nur Strings eingefügt werden können.
Clear zum Beispiel schmeißt wieder alle Elemente raus, ja,
da ist eine Frage. Ja. Ja. Ja,
da wird auch noch die Präferenz übergeben. Richtig, es wird
immer nur eine Referenz übergeben in Java. Also an dieser Stelle hier,
wenn ich da, sagen wir, etwas Lachs sage,
da wird ein Objekt übergeben, dann wisst ihr alle,
hoffentlich jetzt, dass da natürlich kein Objekt übergeben wird,
sondern nur eine Referenz auf ein Objekt,
weil überhaupt nur Referenzen in Java hin und her geschubst werden
zwischen Methoden.
Hier mal als Beispiel einer Set benutzen,
dass ihr nochmal so ein bisschen, ein bisschen einfacheres,
kleineres Beispiel seht, wie man so ein Set benutzen kann.
Also hier wird eine Variable deklariert, Babynamen. Dieses Beispiel ist ziemlich blöd,
ich weiß, ja, aber es ist einfach illustrativ.
Man kann so ein paar Dinge daran zeigen. Also wir
haben eine variable Babynamen vom Typ, Set of String.
Das heißt, ich gebe tatsächlich den Element-Typ bei der Deklaration einer Variablen an.
Und dann wird dieser Referenzvariablen eine Referenz zugewiesen auf ein Hash-Set von String.
Also ein Hash-Set ist eine Implementation des Set-Interfaces.
So, und dann kann ich tatsächlich jetzt über Babynamen
Zum Beispiel Abfragen, wie viele Intermine sind denn drin?
Ich habe noch nichts reingetan in diese Menge.
Also ist die Menge noch null. Dann hätte ich hier
verschiedene Namen klarer, Anna, Annika, Anna.
Okay, da hat also jemand Brainforming gemacht,
schmeißt irgendwelche Namen rein. Anna wird hier doppelt reingeworfen.
Wie viele haben wir schon? Jetzt gucken wir mal nach,
wie viele haben wir denn schon gesammelt in unserem Babynamen-Container?
Na, der ist jetzt natürlich drei, weil Anna beim zweiten Mal ein Duplikat war.
Da kommen wir schon in diese Richtung, wann ist das denn ein Duplikat?
Also hier Anna zweimal eingefügt, wird als Duplikat angesehen. Dann,
wenn ihr, If Baby, wenn noch nicht,
also if not, Baby namen Contains,
also wenn Julia noch nicht enthalten ist, dann, oh,
Julia, finde ich super, soll auch noch mit rein.
Annika, ist nicht gut, wird wieder rausgeschmissen,
also Baby namen Remove, Annika.
Und dann ist die Baby namens Size immer noch drei,
weil wir den einen rausgeschmissen haben, aneinander dazugepackt haben.
So, das war jetzt ein blödes Brainstorming,
alles nicht gut, deswegen nochmal von vorne Baby namens Clear.
So, einfach, dass ihr seht,
man kann eben halt sehr einfach mit diesen Sammlungen umgehen.
So ein paar zentrale Eigenschaften von dem Interface-Set. Erstens,
ein Set definiert keine Ordnung der Elemente. Das heißt,
man weiß nicht, in welcher Ordnung die da reinkommen.
Also wenn ich was reinpacke und dann alle wieder raushole,
weiß ich nicht, in welcher Reihenfolge die wieder rauskommen.
Die Semantik von Ed, also diese Operation, um ein Element hinzuzufügen,
ist so definitiv, dass keine Duplikate eingefügt werden dürfen.
So, und jetzt kommt genau die Beantwortung der Frage
von vorhin, wonach richtet sich das denn?
Wann ist denn etwas ein Duplikat? Das ist ganz einfach,
die Gleichheit von Elementen wird mit der Operation Equals geprüft.
Equals werden wir uns gleich ansehen, genauer ansehen,
die ist also eine Operation, die für alle Typen in Java definiert ist.
Und zwar formal gilt für alle Elemente innerhalb einer Sammlung,
eigentlich einer Menge, also alle elementierten anderen Sets,
Die unterschiedlich sind, dass dann auch garantiert gelten muss,
dass die nicht gleich sind.
Die müssen sich also tatsächlich in Hinsicht auf die Operation Equals.
Also die dürfen nicht gegenseitig gefragt, ob sie equal sind
darf, dürfen nicht zwei Elemente True liefern.
Und diese Massenoperationen sind hier die mathematischen Mengenoperationen, Contains all,
also Untermenge, Ad-all, Vereinigung, Remove-all, Schnitt,
Mengendifferenz und Retain-all, geschnittene Schnittmenge.
Jetzt nochmal auf das Equals. Das ist ganz wichtig. Also,
Jede Klasse in Java bietet automatisch alle Operationen an,
die in der Klasse Java Lang Object definiert sind.
Also wenn wir hier nochmal diese wunderschöne Doku haben,
dann hatte ich ja vorhin hier Java Lang gesehen.
Ah, Java Lang hier, das ist das Paket.
In diesem Paket gibt es so verschiedene Dinge, unter anderem die Klasse Object.
Und die beschreibt Operationen, die jeder Typ, jeder Referenztyp in Java anbietet.
Also hier gibt es Operationen wie Equals, aha,
dann gibt es so Dinge, die müssen wir noch nicht unbedingt verstehen,
die sind auch überhaupt nicht Thema, Clone, Finalize,
Get Class,
Hashcode werden wir gleich nochmal sehen
Und to string. Kennt ihr vermutlich auch schon so ein bisschen,
weil wenn ihr irgendwo hingeschrien habt,
System out printal und irgendeinen beliebigen Objekttyp übergeben habt,
dann wird an dem Objekt, was da übergeht,
mit einer Referenz, wird dann aufgerufen, to stringen.
Und dann wird letztendlich die Zeichenkette auf der Konsole ausgegeben.
Also jedes Objekt in einem Java-System kann sich in eine Zeichenkette umwandeln.
Nicht umwandeln, sondern kann als Zeichenkette sich darstellen.
Das ist einfach so. Und es gibt eben halt auch
diese Operation Equals. Indicates whether some object is equal to
this one.
Wenn wir das haben, das heißt,
ich kann jedes Objekt über diese Operation fragen,
ob es gleich ist, mit dem als Parameter angegebenen Objekt.
Und da kann eine beliebige Referenz übergeben werden. Wirklich eine beliebige Referenz.
Die muss nicht von einem bestimmten Typ sein. Die Standard-Implementation,
also was, wenn ihr nichts tut,
wenn ihr eine Klasse schreibt und ihr macht nichts mit dem Equals,
ihr definiert kein eigenes Equals, dann ist Equals so implementiert,
automatisch, dass Referenzen verglichen werden.
Dann ist das das Gleiche, als wenn ihr
die Referenzen auf gleich gleich vergleicht.
Ich zeige das hier mal an diesem Beispiel. Nein,
ich habe noch ein anderes Beispiel.
Warte, ich habe hier noch
ein anderes Beispiel
Das hier, das werdet ihr auch diese Woche in den Übungen ein bisschen bearbeiten.
Möglicherweise. Bitte? Oh, da ist eine Frage,
ja. Das ist schon eben bei den Mengen der Mengen.
Es ist erlaubt, einfach eine Knallreferenz in eine Länge einzunehmen.
Dann geredet die Frage auf all der Bewegung, die ich zu verdient jetzt aufzumachen.
Oha, das ist eine ganz schwierige Frage. Achso,
die Frage war, wie ist es denn,
wenn man Knall einfügt in eine Menge?
Das ist cool. Das, was ich jetzt selber auch
nicht so genau, Dann machen wir doch mal eine Menge.
Juhu, das machen wir jetzt. Wir definieren,
also ich komme da drauf zurück, ja.
Wir haben hier ein Projekt, das ihr auf Aufgabe 4 dieser Woche bearbeiten sollt.
Da geht es um das Geburtstagsparadoxon. Das besagt,
wenn irgendwie zwei Leute auf einer Party,
wenn man Leute auf einer Party fragt,
wann sie deinen Geburtstag haben, an welchem Tag im Jahr,
also was weiß ich, 30. Januar oder so,
dann ist schon bei einer relativ kleinen Party die Wahrscheinlichkeit ziemlich groß,
dass zwei Leute am gleichen Tag Geburtstag haben.
Das ist so ein
mathematisch spannendes Ding
Und das sollt ihr dann auch mal hier so ein bisschen softwaretechnisch untersuchen.
Und da habt ihr ja so hier so eine Interface-Party,
da kann man dann irgendwie Geburtstage reinstecken.
Also mehrere Leute sagen, wann sie Geburtstag haben,
dann werden die sozusagen gesammelt. Und dann wird das Ganze
ein bisschen simuliert, da müsst ihr eine Klasse bauen,
die dieses Party-Interface implementiert. Darum geht es gar nicht,
sondern hier ist eine Klasse angeboten, schon von uns geliefert,
die heißt Tag und die modelliert einen Tag im Jahr.
Ich kann also jetzt hier einen Tag erzeugen,
zum Beispiel den 30. Tag, das ist nicht der 30.,
sondern doch, angefangen bei null. Das heißt also,
Paar am Tag Nummer ist Tag des Jahres im Intervall, 0 bis 366.
Das heißt, wenn ich jetzt hier 30 eingebe,
dann habe ich hier ein Exemplar und das ist to string,
liefert mit den 31. Januar.
Also null ist der 1. Januar, eins der zweite und so weiter.
Also ist dann 30, der 31. Januar.
So. Und wenn ich jetzt diesen von diesem Tag noch
ein Exemplar zeuge und jetzt nochmal den 30. Tag wähle,
dann habe ich hier jetzt auch to string ein Tagobjekt,
das den 31. Januar darstellt.
Ich habe also zwei verschiedene Exemplare derselben Klasse,
die aber logisch denselben Tag modellieren
Gut. Jetzt kann ich als erstes mal fragen,
ist jetzt Tag eins, gleich gleich Tag zwei.
So, was kommt da raus? Falls, da kommt Falls
raus, klar, weil es zwei verschiedene Objekte sind.
Und wenn ich Referenzen habe auf zwei verschiedene Objekte und die
auf Gleichheit vergleiche, dann liefert das Fouls.
Es sind ja verschiedene Objekte. Und damit auch die Referenzen unterschiedlich.
Was jetzt schön wäre, wenn ich jetzt sagen könnte,
Tag 1.equels, Tag 2. Das möchte ich gerne,
dass das zutrifft
Ich möchte also tatsächlich, dass da jetzt True rauskommt.
Kommt aber nicht raus, da kommt Falls raus.
Das liegt daran, dass tatsächlich in dieser Klasse,
die ich jetzt hier in die Vorlesung,
in der Vorlesung verwende, dass Equels nicht redefiniert ist.
Das heißt, ihr könnt dieses Equels redefinieren. Für bestimmte Klassen
ist es sinnvoll, dass ihr eine eigene Definition von Gleichheit festlegen.
Diese Klassen können die vorgegebene Implementation ändern. Also die vorgegebene Implementation
habe ich eben gesagt, die vergleicht einfach nur Referenzen.
Und man kann das ändern. Da ist eine Frage.
Ja, das ist jetzt, dieses Falls,
das ist jetzt nicht letztlich nicht das Salat,
dass da mit zwei verschiedenen Sälen gesprochen hätte
Die beiden mit Tagen. Sie fragt,
ob das jetzt bei dem Vergleich eben daran lag,
dass die an verschiedenen Stellen gespeichert sind.
Jein. Also hier war es jetzt so, ich habe
jetzt den Vergleich auf zwei verschiedene Arten und Weisen gemacht.
Also ich habe einmal habe ich tatsächlich die Referenzen verglichen,
das war dieser Vergleich hier. Da werden die Referenzen verglichen
und weil die Objekte an verschiedenen Stellen im Speicher liegen,
kann man sich auch vielleicht so merken, sind auch die Referenzen natürlich unterschiedlich.
Bei den Equals hier, da möchte ich eigentlich,
das ist der Sinn der Operation Equals, eine vernünftige Gleichheit definieren.
Also wann Objekte als gleich angesehen werden sollen,
dieser Klasse
Und für diese Klasse Tag wäre es schlau,
wenn der 31. Januar gleich dem 31. Januar wäre,
also wenn verschiedene Objekte trotzdem als gleich angesehen würden.
Und das ist erst mal das, was ich jetzt beschreiben will,
dass man in einer eigenen Klasse,
wie zum Beispiel dieser Klasse Tag, dass Equals redefinieren kann.
Also ich kann festlegen, wann zwei Exemplare als gleich angesehen werden.
Okay, das können wir jetzt mal implementieren, das machen wir jetzt mal live.
Ich definiere hier Equals. Und das mache ich einfach so,
indem ich hier eine Operation hinschreibe, die muss tatsächlich genau diese Signatur haben.
Public Bulien, Equals, die muss auch tatsächlich so heißen,
und die muss als Parameter ein Object bekommen.
Object Other, kann man das mal nennen hier. So,
das ist genau die Operation, die hier auch auf der Folie steht,
hier Public Bulien, Equals Object Other.
Die ist für alle Objekte in Java definiert,
das heißt also auch für meine Klasse Tag,
obwohl ich sie ja gar nicht geschrieben hatte, war sie aufrufbar,
weil sie eben halt von Object für alle Klassen automatisch definiert ist.
So, das heißt, wenn ich jetzt aber für meine konkrete Klasse,
für die Klasse Tag jetzt eine besondere Gleichheit implementieren möchte,
dann muss ich als erstes einen ganz blöden Weg gehen.
Ich muss nämlich erst mal sagen, ich bekomme ja hier ein beliebiges Object.
Ich will natürlich nur True liefern, wenn das andere Objekt auch ein Tag ist.
Es muss ja auch ein Exemplar der Klasse Tag sein.
Das heißt, das Erste, was man hier macht,
ist, if, other, instance of Tag,
wenn das nicht der Fall ist, also, if not other,
ich klammere explizit, das ist immer ein bisschen hilfreicher.
So, wenn also das andere Ding, also die Referenz,
die mir übergeben wird, das andere Objekt,
wenn das kein Tag ist, Dann kann ich schon mal sagen,
ich bin da nicht gleich dazu, Return falls.
Das konkrete Objekt, das gerade aufgerufen wird, das gefragt wird,
ob es zu dem anderen Objekt gleich ist, sagt,
wenn das kein Tag ist, kann ich schon mal gar nicht gleich sein.
Tage können nur gleich sein zu Tagen. Wenn das der Fall ist,
oh, jetzt habe ich hier einmal, das mache ich das,
was ich wollte, wenn ich jetzt weiß,
dass das andere Objekt ein Tag ist,
jetzt muss ich den nächsten Trick anwenden,
ich muss jetzt dafür sorgen,
dass ich diese Operationen von einem Tag auch wirklich manipulieren kann.
Das heißt, ich muss jetzt sagen,
ich deklariere mir eine lokale Variable, Und weise jetzt die Referenz,
die ich übergeben bekommen habe, dieser Variablen zu.
Das wird so nicht gehen. So wäre es am schönsten.
Ich weiß ja, ich weiß ja, es ist ein Tag.
Ich habe ja hier gerade festgestellt, das andere ist garantiert
ein Exemplar von Tag. Das heißt, die Referenz müsste
ich doch eigentlich meiner Variablen vom Typ Tag zuweisen können.
Das ist so nicht übersetzbar. Dann sagt er hier, incompetible types.
Ich muss also etwas machen, was man einer Typzusicherung nennt.
Ich sage also an dieser Stelle hier, dass Compiler,
Relax, ich weiß, was ich tue,
das andere ist ein Tag,
sieh es bitte als Tag an und dann kann ich
diese Zuweisung auch machen
So, und jetzt geht das hier fast.
Jetzt fehlt hier noch das Return-Statement. So,
jetzt muss ich natürlich noch meine eigentliche Überprüfung machen,
nämlich ist das andere Ding tatsächlich der gleiche Tag.
Das heißt, jetzt mache ich hier sowas wie Return,
wie heißt jetzt die Exemplar-Variable? Das habe ich
gar nicht gezeigt. Hier ist also diese Nummer gespeichert.
Als Exemplar war ja die Nummer des Tages im Jahr.
Also Tagnummer. Also wenn meine eigene Tagnummer,
wenn die gleich ist, der von dem Tag,
also von diesem anderen Tag, Tag, Punkt, Tag genommen.
Und jetzt kann man hier sehen, dass ich tatsächlich das so schreiben kann.
Ich kann tatsächlich auf die Exemplarvariablen eines anderen Objektes direkt zugreifen,
obwohl das Private ist, weil ich in derselben Klasse bin.
Ich bin in der Klasse Tag, also alle meine Exemplare,
die haben keine Geheimnisse voreinander. So, das heißt also,
so kann man das jetzt übersetzen. Und siehe da,
jetzt ist es so, wenn ich jetzt nochmal zwei Tage Exemplare
erzeuge und dann hier nochmal diese 30er-Exemplare erzeuge, zwei Exemplare,
beide repräsentieren, ich zeige es nochmal, den 31. Januar
Und wenn ich jetzt frage, ist Tag 1,
Equals, Tag 2, dann sollte jetzt True rauskommen.
Und es kommt tatsächlich True raus. Wenn ich jetzt hier
aber irgendwie sage, El String, S ist gleich Banane,
mal wieder meinen Bananen-String. Und jetzt zum Beispiel Frage Tag
1.equals S. Ich kann tatsächlich ein Exemplar von Tag fragen,
ob es gleich ist, beliebigen Objekt zum Beispiel einem String.
Und dann kommt da natürlich False raus, haben wir gerade implementiert.
Wenn es nicht ein Exemplar meiner eigenen Klasse ist,
kann ich gar nicht gleich sein dazu.
So, prima, prima, das ist super.
Jetzt kommen wir auf das andere zurück. Ich möchte jetzt
mal so eine Menge bauen, eine Menge von Tagen.
Ja, also ich deklariere hier mal Java,
You Till Set von Tag. Ich kann also als Elementtyp
von so einer Menge natürlich auch einen Tag angeben.
Jeder Objekttyp ist zulässig. Das sei jetzt mal
mein Set hier,
eine Set-Variable
Initialisiere ich mit einem New Java, You Till Hash,
Set von Tag. So, jetzt habe ich also mein Set,
ist eine Objektreferenz, auf eine Menge von Tagen.
Jetzt kann ich also bei diesem Set,
wir können das einfach mal ein bisschen einfacher machen,
ich ziehe das mal hier rüber,
das ist mein Set, mein Hash,
also eine Menge von Tagen,
da kann ich jetzt hinzufügen mit Ed
einen Tag
So, und jetzt füge ich hier den Tag dazu, ein Exemplar.
Und dann sagt er mir auch, liefert er mir,
ja, hat geklappt, konnte ich hinzufügen.
Wunderbar. Jetzt kann ich zum Beispiel diese Menge fragen,
wie viele Elemente hast du denn drin?
Size ist eins. So, jetzt würde ich hoffen,
dass wir nicht jetzt diesen Tag hinzufügen,
dass dann beim Ad das als Duplikat angesehen wird.
Weil ich habe ja gerade Equiels definiert. Ich habe ja gerade festgelegt,
dass diese beiden Exemplare als gleich angesehen werden sollen.
Wenn ich jetzt also Tag zwei hier reinreiche,
dann liefert er dummerweise immer noch True.
Das heißt, da ist irgendwas schiefgelaufen. Das heißt,
jetzt habe ich in meiner Menge Sei es tatsächlich zwei Elemente drin.
Ich möchte, dass zwei Tage, zwei Tageexemplare,
die beide den gleichen Tag repräsentieren, als gleich angesehen werden.
Das scheint aber bei dem Set jetzt nicht zu klappen.
So, jetzt will ich noch mal eben eine Sache probieren,
nur um das mal eben die Frage zu beantworten.
Jetzt kann ich ja bei dem S, bei dem Set,
kann ich ja jetzt einfach mal sagen, Set.at, null.
So, kann ich ja einfach mal hin,
einfach mal ausprobieren, was dann passiert?
Ja, mach da. Man kann also tatsächlich
eine null Referenz auch hinzufügen.
Ah, das ist eine gute Frage. Wir gucken mal
. Size, jetzt sagt er, er hat drei.
Also, Nald ist jetzt mit drin, ja?
Ja, das ist tatsächlich nicht gleich zu allen anderen.
Also, es ist das, die meisten E-Quills-Implementationen von Objekttypen
liefern nicht True by Null.
In diesem Fall also dürfte das hier entsprechend... So,
das heißt also, man muss da ein bisschen aufpassen mit den Null-Referenzen.
Aber das habt ihr wahrscheinlich auch schon an anderen Stellen mitbekommen.
So, warum klappt das jetzt hier nicht?
Das ist ja jetzt eigentlich ziemlich Ärger.
Ich habe mir jetzt die Mühe gemacht,
hier euch live zu zeigen,
wie man
das E-Quills redefinieren kann
Und das ist auch wunderbar. Also zum Beispiel bei String
habt ihr das auch schon gesehen, dass man ja,
dass es redefiniert ist bei String und dass man das auch benutzen sollte,
wenn es erst mal redefiniert ist.
Das Problem ist, Equals on Hashcoat hängen sehr eng zusammen. Und zwar,
wenn ihr jetzt in diese Doku von Object mal reinguckt,
dann steht hier bei Equals ein ziemlich wichtiger Satz.
Note that it is generally necessary to overright the hashcoat
method when ever this message is overrhythm.
Suest to maintains a general contract for the hashcoat method which
stated equal objects must have equal hashcoats.
Aha, da steht also einfach nur jetzt ganz banal in
der Klasse Object
Steht dieser Text drin. Aber dieser Text gilt für alle
Java-Klassen. Wenn sich irgendeine Java-Klasse da nicht dran hält,
dann hält sie sich praktisch nicht an die Sprachregeln. Das heißt,
wir haben jetzt hier eine komische Regel, die sagt,
wenn ich Equals redefiniere, dann muss auch Hashcode redefiniert werden.
Also wenn wir für zwei Objekte in einer Klasse selbst festlegen wollen,
wann zwei Exemplare als gleich anzusehen sind.
Und Equals redefinieren, dann müssen wir auch Hashcode definieren.
Ich werde jetzt heute nicht erklären, warum das so ist,
aber ich werde es in einer der nächsten Vorlesungen erklären.
Hashing, das liegt daran, dass diese Implementation,
die wir benutzt haben, diese Hash-Set-Implementation,
basiert auf einem Hash-Verfahren die benutzen diesen komischen Hashcode.
Diesen Hashcode kann ich tatsächlich auch aufrufen.
Ich kann tatsächlich hier bei diesem Projekt bei Tag aufrufen,
Tag, ach, was habe ich hier?
Tag 1, genau. Tag 1.hashcode. Und das liefert
mir irgendeinen Hashcode. Also ich kann jedes Objekt,
das ist auch wieder eine Operation in der Klasse Object.
Jedes Objekt kann ich nach seinem Hashcode fragen.
Es liefert einfach ein Int, irgendeinen beliebigen End. Ja,
und weil wir jetzt aber Hashcode nicht implementiert haben,
das wird, den wir jetzt machen,
ja nochmal uns ein bisschen angucken, Ich implementiere es jetzt einfach mal.
Das heißt also, diese Methode, Hashcode,
dann machen wir es mal komplett vollständig richtig.
Public Int, Hashcode. So, und das Ding muss
irgendeinen Intwert liefern. Und das Entscheidende ist jetzt,
wenn zwei Objekte als gleich angesehen werden,
also wenn Equals True liefert, dann müssen beide den gleichen Hashcode liefern.
So, jetzt habt ihr mal einen Vorschlag,
welchen Intweer liefern können hier an dieser Stelle,
um dann diese Dings zu erfüllen.
Einfach die Tagnummer, ganz genau.
Wir sagen jetzt einfach hier Return
Unterstrich-Tag-Nummer. Das ist die Exemplarvariable, die ja die Nummer im Larr hält. So,
wenn wir das jetzt übersetzen, und jetzt, juhu,
können wir eigentlich hier das, was wir vorher gemacht haben,
ich mache mir wie nochmal ein Set auf Tag,
ja, dann habe ich hier dieses Set,
ziehe mir die Referenz mal hier rüber.
Jetzt kann ich mir mal wieder zwei Tage erzeugen,
mal wieder den 31. Januar und das Gleiche
nochmal,
Also habe ich jetzt hier to string, 31. Januar,
nee, was nicht, wie ihr es noch mal glaubt,
auch hier to string, 31. Januar.
Beide möchte ich jetzt einfügen in dieses Set, also kann ich jetzt hier sagen, add.
Okay. Er liefert Metrue. Und wenn ich jetzt noch mal das versuche einzufügen,
das hier, jetzt Tag 2,
dann solltet ihr mir hoffentlich Fords liefern, weil jetzt,
weil wir das Korrekt implementiert haben,
also Hashset und Hashcode und Equals, jetzt liefert er mir Fords.
Juhu. Also jetzt haben wir Tag richtig implementiert und es
kann jetzt in den Mengen des Collections-Framework auch korrekt verwendet werden.
Und das ist einer, der häufig, der am häufigsten
gemachten Fehler mit Java, dass Leute Equals überschreiben und Hashcoat nicht.
Das passiert noch richtig fortgeschrittenen Programmierern, ja? Gibt alles
, was der erste Brauchzeit sein hat, sofort Möglichkeiten.
Das ist eine ganz spannende Frage. Er fragt,
ob es so ist, dass wenn man,
also ich habe gesagt, wenn man Equals überschreibt,
dann muss man auch Hashcoat passend dazu überschreiben.
Aber wie ist es, wenn man Hashcoat überschreibt,
muss dann Equals auch überschrieben werden
Das nein. Es ist tatsächlich möglich, den Hashcode zu
ändern, solange der Contract eingehalten ist. Das heißt,
solange zwei Dinge, die bei Equals als gleich angesehen werden,
den gleichen Hashcode liefern, ist das in Ordnung.
Das heißt, das kommt aber erst später,
wenn wir über Hashcode, über Hashing nochmal reden.
Es darf zum Beispiel nicht so sein,
dass dasselbe Objekt zu verschiedenen Zeitpunkten einen unterschiedlichen Hashcode liefert.
Weil das Equals, das, wie es vordefiniert ist,
macht ja einen Referenzvergleich. Das heißt, wenn ich zwei
Referenzen auf dasselbe Objekt vergleiche, mit Equals kommt True raus,
Und dann müssen die den gleichen Hashcode liefern.
Und dann wäre es einfach komisch, wenn das sich ändern könnte.
Also der Hashcode, da kommen wir nochmal ausführlicher drauf.
Also dass man den redefinieren kann und nicht,
also das ist nicht sozusagen beidseitig bedingt.
Wenn das eine, dann muss das andere,
aber wenn das muss nicht das eine.
Okay. Gut, das erstmal nur als Maßgabe.
Die Erklärung dafür folgt. Das ist sozusagen eines der Mysterien
von Java-Programmierung, die viele nicht beherrschen. Gut,
dann haben wir noch ein bisschen Zeit für das Interface List.
Das ist jetzt im Vergleich dazu
relativ einfach
Auch wieder generisch definiert. Ich habe solche Operationen,
erstmal alle Operationen wie Insert. Das heißt also,
ich habe mein Ad, ich habe meinen Contains,
ich habe meinen Size, ich habe mein Empty und all das.
Wirklich alle Operationen genauso. Und dann geht es zusätzlich indexbasierte Operationen.
Also Dinge Operationen, die sich auf bestimmte Positionen beziehen.
Also zum Beispiel meiner Liste kann ich sagen,
gib mir mal das,
ob das Element an Position 3. Oder setze es genau an,
eine bestimmte Position.
Oder füge es an der Position ein
Remove, ich kann auch ein bestimmtes Element, also bezogen auf die Indexposition entfernen.
Ich kann mir den Index liefern lassen und so weiter. Also da seht ihr,
da sind diese ganzen Indexbasierten Operationen, kommen da dazu,
weil eine Liste ja eine Idee hat von Positionen,
die eine Menge nicht hat.
Hier nochmal Beispiel an der Listenbenutzung, also wir haben diese Aufsichtsliste für die Pausenaufsicht,
das war das Beispiel, was Opfolie 60 irgendwann mal war.
Die 60 ist eigentlich natürlich Quatsch, das musste ich in dieser Vorlesung,
war es wahrscheinlich Folie, was auch immer.
Stimmt wahrscheinlich im Skript auch nicht, diese Nummer, fürchterlich,
schlecht gewartet. Aber was ich eigentlich sagen will, ist,
ich habe dieses Beispiel vorhin gesehen, diese animierte Folie,
Also hier die Aufsichtsliste ist eine Liste von Strings und dann nehmen wir irgendeine Implementation daher,
zum Beispiel Clinklist, dann fragen wir erst mal,
wie groß bist du denn, Liste?
Dann sagt er, ich habe nichts drin,
dann fügen wir hier mehrere Elemente ein.
Die Duplikate sind erlaubt, also ist tatsächlich hier,
weil wir Peter hier zweimal eingefügt haben, sind aber tatsächlich fünf Elemente drin.
Dann kann ich an einer bestimmten Position Jan einfügen und
ich kann dann Last Index of Peter,
ich kann also tatsächlich das letzte Auftreten von Peter entfernen.
Genau das, was ich vorher auf der animierten Folie
gezeigt habe, ist hier, ist einfach mal auskodiert.
So kann man so eine Liste benutzen. Okay,
was ganz Wichtig ist, sowohl für Listen als auch für Mengen,
ist, dass man über alle Elemente einer Sammlung iterieren kann.
Das gibt nämlich die sogenannte neue oder Advanced Extended Form,
nee, wie heißt die? For each Loop,
die neue Vorschleife. Die ist anders als die Forschlage,
die ihr kennt. Die sieht nämlich so aus,
nehmen wir mal an, ich habe eine Methode, Liste ausgeben,
die bekommt als Parameter eine Liste von Personen, Personenliste.
Dann kann ich tatsächlich so etwas hinschreiben vor,
und jetzt deklariere ich mir eine lokale Variable,
ähnlich wie bei der anderen Forschleife, vor Person P.
Und dann liest man diesen Doppelpunkt wie ein In.
Also für jede Person P in der Personenliste mache er folgendes.
Und dann wird tatsächlich hier dieser Rumpf so oft ausgeführt,
wie Exemplare, wie Elemente, sorry, wie Elemente in der übergebenden Liste sind.
Wenn da also drei Elemente drin sind,
dann wird dieses System Outprinting mit jedem Element der Liste einmal ausgeführt.
Das ist extrem nützlich. So eine erweiterte Vorstoffe, etwas
mit allen Elementen machen. Das geht tatsächlich auch mit,
sowohl mit Mengen als auch mit Listen
Ja. Gut. Dann einfach der Vergleich nochmal.
Die neue Vorschleife ist ausschließlich für Sammlungen vorgesehen.
Also sie sollte man wirklich speziell da benutzen.
Man sollte sie auch nur da benutzen,
wenn man an der Sammlung selbst nichts ändern will.
Also wenn ich einfach nur mit allen Elementen was machen will,
alles prima. Sobald ich an der Sammlung etwas ändere,
also zum Beispiel durch die Elemente durchgehe,
dann entscheidet es die aus der Sammlung raus sollen.
Nicht gut geeignet, die Vorschleife. Das lässt das eigentlich
nicht zu. Man darf nicht,
während man eine Vorschleife, erweiterte Vorschleife benutzt,
die Sammlung ändern
Es fehlt auch immer ein Index,
wenn die ja tatsächlich in eurem Schleifen Rumpf irgendwie so einen Index braucht,
also so einen Zähler, wie viele Schleifendurchläufe schon passiert sind,
da ist die klassische Vorschleife besser geeignet.
Die klassische Vorschlage ist allgemein immer besser geeignet,
wenn ihr eigentlich die Anzahl der Durchläufe schon kennt.
Das wird ja auch gerne als Zählschleife bezeichnet. Und Wildschleifen immer dann,
wenn man vorab nicht weiß, wie viele Elemente habe ich denn,
also zum Beispiel in dem Einleser eben,
wo ich diese Texte eingelesen habe, habe ich einfach gesagt,
solange Zeilen da sind, ließ sie einen aus der Datei.
Das ist so was ein klassisches Beispiel,
wo man sagt, ließ einfach so lange ein,
bis keine Zeile mehr da ist.
Okay, letzter Punkt für heute,
die Rapperklassen
Das ist jetzt, sagen wir, eines der dunklen Kapitel von Java.
Jetzt müssen wir uns damit auseinandersetzen, dass die Sprache,
dieses zweigeteilte Typsystem hat. Ich habe jetzt schon mehrfach gesagt,
es gibt die primitiven Typen, also in Bulien,
Char, kennt ihr alles schon.
Und es gibt den ganzen Rest, die ganzen Referenztüten.
Alles, was ihr selbst definiert an Klassen,
definiert neue Referenztypen. Entscheidend ist, bei dem Collections-Framework,
bei den ganzen Collections in Java, die können nur Referenzen enthalten.
Ihr könnt nicht einfach einen Int in eine Set einfügen
Damit das aber dann doch geht, weil man es ja manchmal braucht,
dass man einfach nur ein paar Zahlen haben will,
also eine Menge von ganzen Zahlen oder eine Liste von bulschen Werten,
haben die Java-Leute gesagt, na gut,
dann bieten wir eben halt ein paar Klassen an,
die nur dafür da sind,
diese primitiven Werte einzupacken in so Stellvertreterobjekte.
Das heißt, für Int gibt es eine Rapperklasse Integer und
für Bulien gibt es eine Rapperklasse Bulien und so weiter.
Und darin packe ich dann solche Dinger ein. Das heißt,
ich kann jetzt hier tatsächlich sagen, New Integer 5,
dann kann ich ihn einfach so auf.
Und da habe ich hier eine Objektreferenz, die kann ich mich ja auch rüberziehen.
Dann habe ich tatsächlich eine Referenz auf ein Objekt vom Typ Integer
und kann mir hier den Int-Value geben lassen.
Und dann kriege ich fünf raus, überraschend.
Also das ist ein Objekt, das nichts weiter tut,
als den Wert fünf zu kapseln.
Nur damit ich dann dieses Objekt in eine Sammlung einfügen kann.
Das ist ein bisschen blöd, ein bisschen unschön. Was noch dazu kommt,
ist, dass sie dann irgendwann gesagt haben, naja,
Wenn ich sowas habe wie ein Intager,
hier so ein Eye-Rapper, also ich habe ein Zeuge,
einen Intager, mit dem wäre 42.
Die Referenz auf dieses Wertobjekt kann in eine Menge eingefickt werden.
Ich habe ein Set auf Intager, also der Element-Typ
muss immer ein Referenztyp sein, also Set of Intager.
Dann kann ich da diesen Rapper einfügen.
Und dann kann ich auch tatsächlich das wieder rausholen,
also tatsächlich hier bei dem Eye-Rapper über Int-Value,
das mir den Wert wieder rausgeben lassen.
Für Bullshit-Werte läuft das analog. Das ist erstmal diese Logik von,
ich hole den Wert,
den dieses Objekt verpackt da raus oder packe ihn da rein,
Boxing und Unboxing,
also verpacken und entpacken
Dann haben Sie mit 1,5 eingeführt, dass das automatisch passiert. Das heißt,
ich kann tatsächlich so überschreiben, wie List of Intager,
ja, und ich füge dann tatsächlich ein I ein.
Das heißt, als aktueller Parant,
da steht da ein Int, dann sieht der Compiler,
oh, das ist eine Liste von Intagers,
es wird als aktueller Parantar ein Int angegeben.
Ich weiß ja, was der Benutzer will. Ich packe mal
den Int in ein Inteager-Objekt ein und dann wird das da reingepackt.
Also das ist sozusagen, wird automatisch gemacht.
Und genauso, wenn ich das dann hier mache,
ich kann tatsächlich das auch wieder entpacken.
Ich muss mir also den Ei-Rapper gar nicht jetzt sagen,
gib mir den Int-Value, sondern einfach nur weise dieses Inteager-Objekt,
dem primitiven Typ zu und es geht.
Weil das automatisch wieder entpackt wird. Dann macht der Compiler
so ein bisschen was hinter den Kulissen.
Und das führt dazu, dass sowas passiert. Ich habe
eine Integer-Variable A und sage hier, das wird initialisiert mit New Integer 5.
Dann eine weitere Variable in B vom Typ Int,
mit dem Wert 5 und intischer C,
mit dem Wert 5. Normalerweise gilt bei Gleichheit, dass sie transitiv ist.
Also wenn A gleich B ist und B ist gleich C,
dann gilt eigentlich, dass A auch gleich C ist.
Das gilt hier plötzlich nicht mehr. A ist gleich B,
also wenn ich diese beiden vergleiche,
dann wird das Integer-Objekt ausgepackt und die 5 wird rausgeholt,
dann werden die beiden fünf und vergleichen
jung sind gleich
Bei B gleich C, das Gleiche. Da wird also
auch hier angeboxt, geentboxt, wie auch immer, entpackt.
Aber A und C sind verschiedene Referenzen. Verschiedene Objekte. Und
dann wird tatsächlich hier, wird das hier ungleich liefern.
Ist nur so ein kleines Detail, das sind die Rapperklassen,
die muss man auch kennen, muss man wissen,
dass man, wenn man primitive Typen in Sammlung einfügen will,
dann macht man das mit den Rapperklassen.
So, letzter Satz für heute, welche Sammlung ist richtig
für meine Zwecke? Das ist problemabhängig. Also wenn ihr
für ein bestimmtes Problem irgendwie Sammlungen braucht, überlegt euch genau,
was für eine Art von Sammlung wollt ihr?
Ihr habt diese Tabelle gesehen, dann sucht euch eine geeignete Sammlung raus.
Es gibt da alles Mögliche dazu im Collections Framework,
vor allen Dingen prominent sind immer Mengen und Listen.
Aber ihr müsst euch fast immer entscheiden,
will ich eine Menge oder bin ich eine Liste?
Und dann müsst ihr euch überlegen, sind die Dopplikate wichtig oder nicht?
Ist die Reihenfolge wichtig? Und dann sollte auch in
eurem Klientencode immer nur dieser Typ des Interfaces verwendet werden.
Auswahl einer Implementation ist dann der zweite Schritt.
Also für Listen gibt es zwei Implementationen, Arrailis und Linklist.
Die Unterschiede sehen wir uns noch an in dieser Veranstaltung.
Und für Set gibt es eben falsch zwei Implementationen,
Hashtag and Treeset. Das heißt, das sollte ein zweiter
Gedanke sein, welche ist denn die effizientere Umsetzung dafür
So, dass sie Zusammenfassung und ich habe natürlich nochmal eine Storesi-Frage.
So, dann müssen wir jetzt nochmal eben hoffen,
dass es jetzt auch funktioniert. Ich habe es nämlich jetzt nicht getestet,
Abstimmung, Vorlesung 9, Juhu, mal schauen.
Welche der folgenden Aussagen gilt nach Ausführung dieses Quelltextes? So,
ihr seht hier, ich lasse das schon mal laufen.
Abstimmung gestartet, Clicker, habt ihr hoffentlich alle,
die Abstimmung läuft, es kommen schon die ersten Stimmen.
Seht euch den Quelltext an, eine Menge von Strings hier
Irgendwelche Dinge hinzugefügt und dann wird ein bisschen was überprüft.
Dann wird noch was wieder rausgeholt mit Remove.
Und dann sollte er einfach sagen, was dann gilt,
welche der folgenden Aussagen. Klassische Klausuraufgabe. Wenn ihr verstanden habt,
wie Mengen funktionieren, ist es eigentlich relativ einfach zu beantworten.
Also diese grundlegenden Eigenschaften von Mengen und Listen Wenn man
sie verstanden hat, ist es alles ganz einfach.
Ach, das war nach Zeiten, als hier irgendwie schon
nach 5 Sekunden irgendwie 150 Stimmen da waren.
Aber es läppert sich zusammen. Wir kommen schon bald auf
100 hier. Die Entscheidungen werden getroffen. Ja,
das ist gut
So, ich glaube, bei 100 können wir schon mal so ein bisschen hier das beenden.
Da haben wir schon eine relativ signifikante Aussage.
Ich halte das mal an. Wir gucken mal auf die Verteilung. Okay,
das sieht schon mal nach einem klaren Votum aus,
das heißt also über 50 Prozent sind der Meinung,
das länge 1, den Wert 2 hat. Ja,
okay, also Länge 1,
an dieser Stelle eine Menge Punkt 2,
da haben also alle gesehen, dass hier zweimal dasselbe Element eingefügt wird,
deswegen die Menge des Sis nicht 3 ist,
sondern 2. Und dann ist tatsächlich auch B die richtige Antwort,
das heißt, das ist die richtige Antwort.
Das ist wunderbar, sehr schön, immer beruhigend zu sehen,
dass die Dinge, die ich erklärt habe,
auch offensichtlich ganz gut angekommen sind.
Nächste Frage. So, letzte Frage für heute.
Da könnt ihr jetzt noch mal euch das ein bisschen dran.
Welche der folgenden Quelltexte sollte anstelle der Unterschiede?
Also hier sind so ein paar Unterstriche bei dieser Vorschleife hier,
damit in einer Vorschleife alle Elemente der Sammlung bearbeitet werden.
Da gibt es hier verschiedene Möglichkeiten, was da jetzt stehen kann.
Und ihr sollt einfach nur sagen, welches gilt da
Welches würde da dafür sorgen, dass tatsächlich, also ihr seht,
hier wird ein Set auf Person übergeben als Parameter,
dann soll irgendwie durch die Elemente dieser Sammlung durchgegangen werden und
dann kann man anscheinend irgendwie an so einer Person aufrufen,
Beitrag, da wird also irgendwie so ein Beitrag aufsummiert.
Die Semantik ist ziemlich wurscht, hier geht es darum,
wie sieht das hier aus,
damit tatsächlich alle Elemente in der Sammlung bearbeitet werden?
Hier sind die vier Möglichkeiten
Die Zeit ist fast rum. Wir haben
fast 100 Stimmen. Ich löse es noch eben auf.
Moment, ich schalte an. Ja. Wir gucken mal
, wie so das Meinungsbild ist
Oha. 73 Prozent sind der Meinung, ist es.
Und das ist sogar richtig toll.
Dann vielen Dank für eure Aufmerksamkeit heute