Tip
|
Tabelle 11.1 (Schnittstellenübersicht) ist Gold wert! Lernen. |
Tip
|
Hinweis zu Kap. 11.2: Als Java-Entwickler/in müssen Sie all die Methoden kennen, die |
Wenn Sie class A extends B
sehen, wissen Sie, dass B
was an A
vererbt?
Nur wenn es etwas zu vererben gibt, Dinge die private
sind werden nicht vererbt.
Wenn das hier geht Object getSelf() { return this; }
, geht dann auch das Object getSelf() { return super; }
?
super
wird nur verwendet zum Aufruf eines Konstruktors oder zum Zugriff auf Variablen und Methoden. super
alleine verweist aber nicht auf eine Instanz.
Ordnen Sie (siehe letztes Beispiel) die Begriffe A
oder B
zu:
-
Oberklasse
-
Unterklasse
-
abgeleitete Klasse
-
Subklasse
-
generalisierende Klasse
-
spezialisierende Klasse
-
Basisklasse
A
ist die Unterklasse, abgeleitete Klasse, Subklasse oder spezialisierende Klasse. B
ist die Oberklasse, Basisklasse, (Superklasse) oder generalisierende Klasse.
Wann ist die Implementierung eines eigenen Konstruktors in einer abgeleiteten Klasse nicht optional?
Beispiel:
class Super { Super(int x) { ... } } class Sub extends Super { Sub() { // hier würde implizit super() aufgerufen // dieser Konstruktor existiert aber nicht // => es muss explizit super(int) aufgerufen // werden } }
Wenn man eine Methode überschreibt, dann ist die Verwendung einer Annotation üblich. Welcher?
@Override
Eine Method überladen und sie überschreiben ist nicht dasselbe. Erkläre den Unterschied!
Eine Methode überladen heißt, eine weitere Variante der Methode mit gleichem Namen aber unterschiedlicher Anzahl von Parametern oder unterschiedlichen Parametertypen zu deklarieren.
Eine Methode überschreiben heißt, in einer Unterklasse eine Methode mit gleicher Signatur (Name + Anzahl und Typ der Parameter) wie in der Oberklasse zu deklarieren.
class A { int method(int i) { return i+1; } } class B extends A { int method() { return 2; } }
Überschreibt B
die Methode von A
? Oder überlädt B
die Methode?
Das ist ein Beispiel für überladung, da die Methoden nicht die gleiche Anzahl von Parametern haben.
Mit welchem Schlüsselwort kann auf Members (Felder und Methoden) der Oberklasse zugegriffen werden?
super
Wie Sie wissen, ist jede Klasse abgeleitet von Object
. Wenn Sie Code wie class A { }
sehen, welche Ergänzungen daran nimmt der Compiler vermutlich vor?
class A extends Object { }
Kann eine abstrakte Klasse einen Konstruktor haben?
Ja, sie können nur nicht mit new
aufgerufen werden. In einer Subklasse können Sie aber mit super(…)
verwendet werden.
Wenn ich etwas super(…)
machen will, wohin damit?
In die erste Zeile des Konstruktors der abgeleiteten Klasse.
Ich möchte gerne den Konstruktor der Ober-Oberklasse aufrufen. Wie geht das?
Direkt geht das nicht, man kann nur auf die direkte Superklasse zugreifen und die muss dann wieder ihre Superklasse aufrufen. Siehe auch: http://stackoverflow.com/questions/586363/why-is-super-super-method-not-allowed-in-java
Hans deklariert eine Klasse als final
, Hannah als abstract
. Was hat Hans mit der Klasse vor, was Hannah?
Hans will, dass man von der Klasse nicht erben kann. Hannah will, dass man von der Klasse erben muss.
Hannah deklariert eine Methode als final
, Hans als abstract
. Woran muss Hans denken, was Hannah egal sein kann? Und was kann Hans sein lassen, was Hannah wiederum tun muss?
Hans muss die Klasse als abstract
deklarieren, Hannah muss im Gegensatz zu Hans die Methode implementieren.
class A { int x; } class B extends A { void foo() { x += 1; } } class C extends A { void foo() { x *= 2; } } A obj = new B(); obj.foo();
Wie kann man diesen Code retten?
Entweder man ändert die letzte Zeile auf ((B) obj).foo()
und castet damit obj
auf einen Typ der tatsächlich die Methode foo
hat, oder man macht A
abstrakt und deklariert die foo
als abstrakte Methode in A
.
class A { void m() { System.out.println("mA"); } } class B extends A { void m() { System.out.println("mB"); } }
Nun: A a = new B()
bzw. B a = new B()
. Was liefert in jedem der Fälle a.m()
auf der Konsole?
In beiden Fällen wird mB
ausgegeben. Der Typ der Variablen entscheidet nicht darüber, welche Methode aufgerufen wird, sondern der Typ des Objektes das sich in der Variablen befindet.
Würde man die Methode m
nicht in B implementieren, würde stattdessen (wegen der Vererbung) in beiden Fällen mA
ausgegeben.
for (Object o : objects) { String s = (String) o; System.out.println(s); }
Ist das eine gute Idee? Warum?
Das ist keine gute Idee, da man in den meisten Fällen einen spezifischeren Typ als Object
verwenden kann und sollte. Außerdem ist der Downcast (String) o
problematisch, da vorher nicht überprüft wurde ob es sich bei dem Inhalt der Object
-Variable tatsächlich um einen String
handelt.
Object o = "abc"; int l = (String) o.length();
Ooops, was ist da schiefgegangen?
Der Cast-Operator bindet schwächer als der .
. Dieser Code versucht die Methode length
von Object
aufzurufen und das Ergebnis zum Typ String
zu casten. Das scheitert aber, da die Klasse Object
keine Methode length
hat. Richtig müsste es heißen in l = ((String) o).length();
Ein …cast passiert implizit, wenn ein Objekt einer Variable von einem Supertyp zugewiesen wird. Ein …cast muss dagegen explizit angegeben werden.
-
Up-
-
Down-
Was bedeutet das Wort "Polymorphie" von seiner sprachlichen Herkunft?
Polymorphie bedeutet "Vielgestaltigkeit". Eine Variable vom Typ List
ist z.B. vielgestaltig, weil das tatsächliche Objekt sowohl eine ArrayList
als auch eine LinkedList
sein könnte.
Eine Klasse, die als class A {}
deklariert wird, wird vom Compiler als class A extends Object {}
aufgefasst. Wie ist das bei class A extends B {}
? Ist eine Deklaration der Form class A extends B, Object {}
oder class A extends B extends Object {}
überhaupt erlaubt?
Auch bei A extends B {}
erbt A
von Object. Allerdings geschieht das nicht direkt. Entweder hat B
keine weitere Oberklasse und erbt damit von Object
, oder die Vererbungskette geht noch einen oder mehrere Schritte weiter, bis die letzte Basisklasse erreicht ist, die dann von Object
erbt.
Die Aussage ist nicht ganz korrekt: "`getClass` gibt die Klasse einer Instanz zurück." Berichtigen Sie den Satz.
getClass
gibt ein Instanz der Klasse Class
zurück, die eine Beschreibung der Klasse enthält.
class Foo { int x; public boolean equals(Object other) { if (other instanceof Foo) { Foo f = (Foo) other; return f.x == x; } return false; } }
Diese Klasse hat laut der Spezifikation der Methode equals
ein Problem. Welches ist das?
Wenn a.equals(b)
den Wert true
ergibt, dann muss auch a.hashCode() == b.hashCode()
gelten. Man müsste also noch die Methode hashCode
überschreiben um diese Eigenschaft sicherzustellen.
Außerdem gehört zum typischen Schema einer equals
-implementierung noch am Anfang eine Überprüfung ob other == this
gilt. In dem Fall kann man sofort true
zurückgeben.
Der Code funktioniert übrigens auch, wenn für other
der Wert null
übergeben wird, da null instanceof X
immer false
ergibt, egal welche Klasse man für X
einsetzt.
Wie sieht schematisch die Syntax einer Schnittstellen-Deklaration aus? [vereinfachte Variante, so wie Schnittstellen meist verwendet werden]
interface Name { typ name(parameter); … }
Die Benennung des Interfaces endet oft auf -able
, um anzuzeigen, dass mit dem Interface irgendeine Fähigkeit bezeichnet wird.
Welche Methodenkörper wären für die Methode hashCode
der Klasse java.awt.Point
zulässig und sinnvoll?
-
return x + y;
-
return x;
-
return y;
-
return x ^ y;
-
return (""+x+y).hashCode();
-
return (x + "," + y).hashCode();
-
return 0;
-
return new Random().nextInt();
Der HashCode soll eine (möglichst) eindeutige Kennung eines Objektes darstellen.
-
return x + y;
kann (1, 4) und (4, 1) nicht unterscheiden (weil+
kommutativ ist). -
return x;
ignoriert die Variabley
und ist daher nicht sinnvoll. -
return y;
ignoriert die Variabley
und ist daher nicht sinnvoll. -
return x ^ y;
kann (1, 4) und (4, 1) nicht unterscheiden (weil^
kommutativ ist). -
return (""+x+y).hashCode();
scheitert für (1, 14) und (11, 4). -
return (x + "," + y).hashCode();
wäre eine sinnvolle Variante. -
return 0;
gibt den gleichen HashCode für jedes Objekt. Das ist nicht sinnvoll. -
return new Random().nextInt();
ist eindeutig, aber das selbe Objekt bekommt bei mehreren Aufrufen von HashCode unterschiedliche codes. Das ist weder zulässig noch sinnvoll.
Zulässig sind prinzipiell alle HashCodes, bei denen sichergestellt ist dass gleiche Objekte (Vergleich mit equals
ergibt true
) auch den gleichen HashCode erhalten. Das ist bei allen dieser Beispiele bis auf return new Random().nextInt();
der Fall.
Was ist richtig?
[ ] interface One extends Two
[ ] interface One implements Two
Die zweite Variante funktioniert nicht.
Wenn man von mehreren Interfaces erben kann, kann man die folgende Syntax verwenden:
interface A { void foo(); } interface B { void bar(); } interface C extends A, B { void baz(); }
Man kann mit Überladung keine zwei Methoden mit gleicher Signatur erstellen. Schließen Sie daraus, was der Begriff Signatur bedeutet.
Die Signatur ergibt sich aus dem Namen, dem Typ und der Anzahl der Parameter.
Eine Schnittstellendeklaration mit genau einer abstrakten Methode heißen?
Funktionale Schnittstelle
Wie können wir Java überprüfen lassen, ob eine Schnittstelle ein funktionales Interface ist?
Mit der Annotation @FunctionalInterface
.
Wie sieht schematisch die Syntax einer Methode in einer Schnittstelle aus, die mit einer Implementierung versehen ist?
Die Methode muss das Schlüsselwort default
haben.
Mit der Nutzung von implements
im Kopf einer Klassendeklaration verpflichtet sich der Rumpf, was zu tun?
Alle Methoden des Interfaces müssen implementiert werden.
Ein Sonderfall wäre eine abstrakte Klasse. Hier kann die Implementierung von Methoden auch an Unterklassen delegiert werden.
Welchen Nutzen haben Schnittstellen außer von einer Klasse eine Implementierungsverpflichtung einzufordern?
Man kann Schnittstellen als Typ im Code verwenden.
Karl sagt: "Wozu Schnittstellen, ich kann auch alles mit abstrakten Klassen machen, was Schnittstellen können." Was antwortet ihm Carla darauf?
Man kann mehrere Schnittstellen implementieren, aber nur eine abstrakte Klasse erweitern.
Carla sagt: "Seitdem es default-Implementierungen bei Schnittstellen gibt, sind abstrakte Klassen überflüssig geworden." Was antwortet Karl darauf?
Abstrakte Klassen können im Gegensatz zu Schnittstellen auch Felder besitzen.
interface I { void foo(); } class A implements I { void foo() {} }
Autsch! Warum?
Die Implementierung von foo
müsste public
sein, weil jede Methode eines Interfaces implizit public
und abstract
ist.
abstract class A { void foo(); }
Aua! Weshalb?
foo
muss als abstract
definiert werden.
interface I { abstract void foo(); }
Geht das? Macht das Sinn?
Das geht, macht aber nicht viel Sinn, da foo
sowieso abstract
wäre, auch wenn man den Modifizierer nicht verwendet.
Die Frage ist angeregt durch den Code auf S.277 aus Kapitel 12.
Geometrie geos = new Geometrie();
Ist Geometrie
eine Klasse oder ein Interface?
Das new
und die runden Klammern für den argumentlosen Aufruf des Konstruktors verraten Ihnen, dass Geometrie
eine Klasse sein muss.
Die Frage ist angeregt durch den Code auf S.277 aus Kapitel 12.
Geometrie[] geos = new Geometrie[4];
Ist Geometrie
eine Klasse oder ein Interface?
Es wird hier ein Array mit Elementen vom Typ Geometrie
angelegt, mehr nicht. Es bleibt nachwievor offen, ob der Typ eine Klasse oder ein Interface ist.