Tip
|
Hinweis: Tabelle 10.1, Modifizierer, müssen Sie können. |
Herr Kofler nennt welche Vorteile, die Objektorientierung bietet?
-
Bessere Strukturierung des Codes
-
Kapselung von Daten
-
Bessere Wiederverwertbarkeit
-
Pakete und Klassenbibliotheken
Wann ist eine Klasse keine Top-Level-Klasse?
-
❏ Wenn die Klasse nicht oben im Quellcode steht.
-
✓ Wenn die Klasse innerhalb von geschweiften Klammern steht.
-
❏ Wenn die Klasse
static
ist. -
❏ Wenn die Klasse
abstract
ist.
Kann man eine Klasse derart in einer Methode deklarieren und nutzen?
void foo() { class StrangeThing { boolean isStrange = true; } StrangeThing thing = new StrangeThing(); System.out.println(thing.isStrange); }
-
✓ Ja, es handelt sich hier um eine lokale Klassendefinition
-
❏ Ja, es ist egal, ob eine Klasse in einer Methode deklariert wird oder umgekehrt
-
❏ Nein, die Klasse müsste
public
sein. -
❏ Nein, die Klasse müsste
static
sein.
Wie sieht schematisch die Syntax zur Deklaration einer Klasse aus [ohne Annotationen und Generics]?
[Modifizierer] `class` Name [`extends` NameOberKlasse] [`implements` I1, I2, ...] `{` // Klassenrumpf (class body) `}`
In einer .java
-Datei können mehrere Klassen deklariert werden. Allerdings gilt eine Einschränkung, was den Namen der Datei angeht. Welche?
-
❏ Der Name der Datei muss mit dem Namen der ersten Klasse in der Datei übereinstimmen.
-
❏ Der Dateiname muss wie der Klassenname mit einem Großbuchstaben beginnen.
-
❏ Der Dateiname muss die Endung
.class
haben. -
✓ Wenn eine der Klassen
public
ist, muss der Name der Datei dem Namen dieser Klasse entsprechen.
Schreibe class test
und schon ist der Kopf ab, bevor auch nur ein {
folgt. Warum? [Gemeint ist Ihr Kopf, nicht der der Klassendeklaration (-:]
-
❏ Vor
class
fehlt einpublic
. -
❏ Es muss
Class test
heißen. -
✓ Es muss
class Test
heißen. -
❏ Der Name
test
ist reserviert und darf nicht benutzt werden.
Namen von Klassen beginnen immer mit einem Großbuchstaben! Zwar ist das eine Konvention, an die sich aber ausnahmslos alle Java-Entwickler/innen halten.
Eine Top-Level-Klasse darf wie nicht deklariert sein?
-
❏ public
-
❏ paketsicher
-
✓ private
-
✓ protected
Gibt es in Java das Laufzeitkonstrukt der Klasse?
Nein. Zu einer Klasse class A {}
gibt es kein Laufzeitkonstrukt, womit man auf die Klasse direkt zugreifen könnte. Mit A.class
erhält man lediglich Zugriff auf ein Objekt, das eine Beschreibung der Klasse A
darstellt. Diese Fähigkeit zur Selbstauskunft über die deklarierten Eigenschaften der Klasse nennt man Reflektion (reflection). Für eine Instanz der Klasse bekommt man mit getClass()
an das Objekt, das die Klasse A
beschreibt.
Gibt es in Java das Laufzeitkonstrukt des Objekts?
Ja. Die Instanzen einer Klasse, gemeinhin als Objekte bezeichnet, existieren ausschließlich zur Laufzeit.
class Thing {
private class PartOfThing {
String name = "part";
}
}
Geht das?
Ja, das geht. Die Klasse PartOfThing
ist allerdings nur innerhalb des Rumpfs von Thing
verwendbar.
class Thing {
private class PartOfThing { }
public PartOfThing pot = new PartOfThing();
}
Wie kann auf pot
innerhalb des Pakets zugegriffen werden?
-
❏
Thing.pot
-
❏
new Thing().pot
-
❏
new Thing.PartOfThing().pot
-
✓ gar nicht
Auf die private, innere Klasse kann von außen weder zugegriffen werden, noch sind Instanzen dieser privaten Klassen zugreifbar, selbst wenn die Klassenvariable public
ist!
jshell> Thing.pot | Error: | non-static variable pot cannot be referenced from a static context | Thing.pot | ^-------^ jshell> new Thing().pot | Error: | Thing.PartOfThing has private access in Thing | new Thing().pot | ^ jshell> new Thing.PartOfThing().pot | Error: | Thing.PartOfThing has private access in Thing | new Thing.PartOfThing().pot
class Thing {
class PartOfThing { }
public PartOfThing pot = new PartOfThing();
}
Wie kann auf pot
innerhalb des Pakets zugegriffen werden?
-
❏
Thing.pot
-
✓
new Thing().pot
-
❏
new Thing.PartOfThing().pot
-
❏ gar nicht
Auf welcher Ebene ist die Klasse class A {}
sichtbar?
Auf der Paketebene. Wenn kein Modifizierer vorhanden ist, ist die Klasse paketsicher.
Was ist eine Klassenvariable? Doch dasselbe wie ein statisches Feld, oder?
Für Herrn Kofler sind "Klassenvariablen" einfach nur beliebige Felder, egal ob sie static
sind oder nicht. Die Terminologie ist hier in der Literatur nicht eindeutig.
Klären Sie die Begriffe "Feld" (engl. field) und "Variable".
"Felder" sind Variablen, die im Rumpf einer Klasse deklariert werden.
class Thing { public String name; }
Kann man auf das Feld name
von anderen Paketen aus zugreifen?
Nein, da man auf die Klasse Thing
nicht aus anderen Paketen zugreifen kann.
Im Rumpf einer Klasse können welche Sprachkonstrukte deklariert werden?
Methoden, Felder, Klassen, Interfaces und Enums.
class Point { private int x,y; Point(int x, int y) { this.x = x; this.y = y; } boolean equals(Point other) { return this.x == other.x && this.y == other.y; } }
Ist der Zugriff auf das private Feld other.x
erlaubt?
Ja, weil die Sichtbarkeit private
sich auf allen Code innerhalb der Klasse bezieht. Es ist egal, welches Objekt auf das Feld zugreift, so lange der Zugriff aus irgendeiner Methode der Klasse Point
erfolgt.
Was ist mit dem Begriff "paketsicher" gemeint?
"Paketsicher" bezeichnet die default-Sichtbarkeit von Klassen und Feldern (wenn kein Sichtbarkeitsmodifizierer angegeben wurde). Auf "paketsichere" Klassen und Felder kann man innerhalb des Pakets zugreifen in dem sie deklariert wurden.
Mit welchem Modifizierer kann man die Voraussetzung für einen immutablen (unveränderlichen) Datentyp schaffen? Reicht die Verwendung dieses Modifizierers allein schon aus, um die Immutabilität zu garantieren?
Wenn ein Datentyp (eine Klasse) immutabel sein soll, müssen alle ihre Felder final
sein. Das reicht allerdings noch nicht aus. Zusätzlich müssen alle Felder selbst einen immutablen Datentyp haben, oder es muss sichergestellt werden, dass niemand sonst eine Referenz auf interne Daten der Klasse haben kann.
Nennen Sie die einzelnen Schritte, die bei einem Aufruf von new
ausgeführt werden.
-
Speicherplatz für die nicht-statischen Felder der Klasse wird zugeteilt.
-
Außerdem wird eine Refenz zu der Klasse angelegt, von der ein Objekt erzeugt werden soll (um z.B. den Code von Methoden nachschlagen zu können).
-
Die Felder werden mit
0
,false
odernull
initialisiert. -
Der Konstruktor wird aufgerufen.
-
Eine Referenz auf das erstellte Objekt wird zurückgegeben.
Wie sieht das Schema zum Zugriff auf eine statische Variable bzw. zum Aufruf einer statischen Methode aus?
Klassenname.variablenname
bzw. Klassenname.methodenname
.
Recherchieren Sie: In der OOP-Veranstaltung hatten wir ein Beispiel, in dem wir eine statische Klassenvariable genutzt haben. Worum ging es bei dem Beispiel? Welchen Zweck hatte die statische Klassenvariable?
Es ging um eine Klasse Thing
mit einer ID, die sich in einem statischen Feld merkt, welche IDs schon vergeben wurden.
class Point { int x = 0, y = 0; Point(int x, int y) { this.x = x; this.y = y; } } Point p = new Point();
Autsch! Warum?
Der Default-Konstruktor existiert nur, wenn kein anderer Konstruktor definiert wurde. In diesem Fall gibt es den Konstruktor Point()
also nicht.
Deklarieren Sie eine Klasse, von der keine Objekte erzeugt werden können.
class Math { private Math() {} }
oder abstract class Thing {}
.
Ein Konstruktor ist mit einer Methodendeklaration sehr vergleichbar. Nur: Der Konstruktor hat zwar einen Namen, ihm scheint jedoch der Rückgabetyp zu fehlen. Warum?
Der Rückgabetyp eines Konstruktors ist immer die Klasse in der er deklariert wurde.
Was sind die Defaultwerte für Felder (Klassenvariablen)? Was sind die Defaultwerte für lokale Variablen?
Die Defaultwerte für Felder sind 0
und false
für primitive Typen bzw. null
für Referenztypen. Lokale Variablen haben keine Defaultwerte.
Warum kann man finalize
nicht für Aufräumarbeiten verwenden?
finalize
wird aufgerufen, wenn der Garbage-Collector das Objekt löscht. Es ist nicht garantiert, wann oder ob das überhaupt geschieht.
Wie ruft man im Konstruktor einen anderen Konstruktor der gleichen Klasse auf? Warum sollte man das überhaupt tun wollen?
this(Parameter);
class A { int a,b; A() { a = 0; this(0); } A(int x) { a = 1; b = x; } }
Autsch! Warum?
Vor dem Konstruktoraufruf this(0);
darf kein anderer Ausdruck stehen.
Im Vorgriff auch das nächste Kapitel: Wie ruft man im Konstruktor den Konstruktor der Oberklasse auf?
super(Parameter);
Was ist die Besonderheit des Interfaces AutoCloseable
? Welche Methoden deklariert es?
Das Interface deklariert nur die Methode close
. Klassen, die das Interface AutoCloseable
implementieren, können in einem try-with-resources verwendet werden.
Ist this
eine Variable?
Streng genommen nein (this
ist ein Schlüsselwort), aber man kann es gedanklich wie eine Variable behandeln.
Ist es nicht das gleiche, ob eine Klasse jetzt ein public int x
definiert oder ein private int x
mit den Methoden int getX()
und void setX(int x)
? Wo liegt der Unterschied?
Mit den Methoden hat man mehr Kontrolle darüber, was mit dem Feld geschieht (z.B. welche Werte bei einem setX
zulässig sind, oder welche Variablen tatsächlich hinter einem getX
steht).
Wozu benötigt man this
?
Um einen Konstruktor in einem anderen Konstruktor aufzurufen und um ein Feld von einer lokalen Variable mit gleichem Namen zu unterscheiden.
Wenn man sich in den Namensgebungen für Parameter und lokale Variablen diszipliniert, benötigt man dann überhaupt noch this
?
Ja, für den Aufruf eines Konstruktors oder wenn this
zurückgegeben oder an eine andere Methode übergeben werden soll.
Wenn an den Konstruktor "falsche" Werte übergeben werden, empfiehlt es sich mit einer Exception darauf zu reagieren. Welche Exception sollte man wählen, sofern man nicht spezifischer sein kann/möchte?
IllegalArgumentException
Wenn es einen Konstruktor gibt, muss es auch einen Destruktor geben, nicht wahr?! Hat Java einen Destruktor? Begründen Sie Ihre Antwort!
Nein, es gibt nur die Methode finalize
, die aufgerufen wird, wenn der Garbage-Collector das Objekt löscht. (Achtung: Es kann nicht garantiert werden ob und wann das geschieht.)
Eine Klasse, die eine close
-Methode anbietet sollte die Schnittstelle AutoCloseable
implementieren. Warum?
Damit die Klasse mit einem try-with-resources verwendet werden kann.
Was ist mit "Settern" und "Gettern" gemeint?
Getter und Setter sind Methoden die das Lesen bzw. Schreiben von internen Daten einer Klasse kontrollieren.
Was ist damit gemeint, wenn man von einer "Datenklasse" spricht?
Eine "Datenklasse" tut nichts anderes als Werte zu speichern. Die Klasse hat dann nur Felder, Getter und Setter.
Wenn Sie Setter- und Getter-Methoden implementieren, dann sollten die Felder wie deklariert sein?
private
Oft sieht man Setter wie public setName(Typ value) { name = value; }
. Was könnte man daran kritisieren?
Dieser Setter macht nicht viel Sinn, da er sich genau so verhält als wäre die Variable name
öffentlich deklariert.
Aufgrund welchen Prinzips der Softwaretechnik werden Setter und Getter begründet?
Es geht um das Geheimnisprinzip, das besagt, dass von außen niemand wissen soll, wie die Datenhaltung innerhalb eines Objekts implementiert ist.
Welcher softwaretechnische Nutzen steckt vor allem in den Setter-Methoden?
Setter ermöglichen es, zu kontrollieren welche Werte für ein Feld erlaubt sind.
Warum ist der Begriff "Unterklasse" für eine innere Klasse problematisch?
Der Begriff "Unterklasse" wird meist für die abgeleitete Klasse einer Oberklasse genutzt. Bitte eine innere Klasse nicht als Unterklasse bezeichnen.
class A {
int x;
class B {
int x;
int foo(int x) {
// zähle alle drei mit x benannten Variablen zusammen
}
}
}
Welcher Code muss an der markierten Stelle stehen, um den Wert von allen drei Variablen zusammenzuzählen? Wie unterscheidet man sie voneinander?
Wir streuen in die Lösung zum Verständnis ein paar Ausgaben ein.
class A {
int x;
class B {
int x;
int foo(int x) {
System.out.println(x);
System.out.println(this.x);
System.out.println(A.this.x);
System.out.println(B.this.x);
// System.out.println(x);
return x + this.x + A.this.x; // this.x oder B.this.x
}
}
}
jshell> new A() $37 ==> A@335eadca jshell> $37.new B() $38 ==> A$B@eec5a4a jshell> $38.foo(3) $39 ==> 3
Eine Top-Level-Klasse als static
zu deklarieren ist sinnfrei, da die Klasse an nichts "hängt" und nur Teil eines Pakets ist.
this.name
oder name.this
, das ist hier die Frage!
Beides ist gültig, je nach Kontext. Im zweiten Fall ist name
jedoch ein Klassenname und sollte eigentlich — unserer Konvention der Großschreibung für Klassennamen folgend — als Name.this
geschrieben werden.
AutoCloseable a = new AutoCloseable() { public void close() { System.out.println("closed"); } }
Warum geht das, obwohl AutoCloseable a = new AutoCloseable();
einen Fehler produziert?
Hier liegt eine anonyme Klasse vor, die nach ihrer Implementierung sofort instanziiert wird.
Kann eine anonyme Klasse einen Konstruktor haben? Warum, oder warum nicht?
Wenn es keinen Namen für die Klasse gibt, sie ist ja anonym (= hat keinen Namen), kann man keinen Konstruktor deklarieren.
class A {
static int b;
class C {
static int d;
}
}
Sie dürfen eine Sache streichen, damit der Code gültig wird.
C
ist eine lokale Klasse, sie darf keine statischen Members haben. Streiche static
bei int d
.
Erzeugen Sie eine anonyme Unterklasse von java.awt.Point
, die die Methode toString
so überschreibt, dass die String-Repräsentation jetzt einfach der mathematischen Schreibweise (x, y)
entspricht. Wie können Sie beim Erzeugen des Objektes dieser Klasse die Koordinaten x
und y
übergeben?
java.awt.Point p = new java.awt.Point() {
public String toString() {
return "(" + x + ", " + y + ")";
}
}
Die anonyme Klasse ist eine Unterklasse von java.awt.Point
.
jshell> java.awt.Point p = new java.awt.Point() { ...> public String toString() { ...> return "(" + x + ", " + y + ")"; ...> } ...> } p ==> (0, 0) jshell> p.x = 10 $41 ==> 10 jshell> p p ==> (10, 0)
Object obj = new Object() { public void myFancyNewMethod() { /* do stuff */ } }
Macht das Sinn?
Die Optik verstellt Ihnen hier vermutlich den Blick. new Object()
ist eine anonyme Klasse, die eine Unterklasse von Object
ist. Der Typ von obj
ist hingegen vom Typ Object
. Wenn man mit obj
eine Methode wie myFancyNewMethod
aufrufen will, beginnt die Suche nach der Methode im Typ Object
, nicht in der anonymen Unterklasse! Die Methode ist also sinnfrei.
Eine Instanz einer anonyme Klasse kann nur auf bestimmte Variablen des Kontextes zugreifen, in dem sie erzeugt wurde. Welche Variablen sind das?
Variablen müssen final
sein.
Definieren Sie, was effectively final heißt?
Eine Variable ist "effectively final", wenn sie zwar nicht als final
deklariert ist, der Compiler aber eine Deklaration mit final
zulassen würde.
AutoCloseable a = () → System.out.println("auto");
Wie nennt man so etwas?
Das ist ein Lambda-Ausdruck, erkennbar am Pfeil →
.
String message = "foo"; AutoCloseable a = new AutoCloseable() { public void close() { System.out.println(message); } }; message = "bar";
Alles in Butter, oder doch nicht?
Das message
nicht effectively final ist, darf die anonyme Klasse nicht auf message
zugreifen.
class A { static int b; class C { static int d; } }
Sie dürfen eine Sache ergänzen, damit der Code gültig wird.
Die Klasse C
muss um ein static
ergänzt werden.
Warum sind laut Herrn Kofler statische innere Klassen gar keine "inneren Klassen" im eigentlichen Sinne?
Die "innere" Klasse ist wie eine eigenständige Klasse behandelbar.