EIDI-Crashkurs 2020 › Crashkurs-Aufgaben zu Polymorphie
- Dieses Thema hat 7 Antworten und 1 Teilnehmer, und wurde zuletzt aktualisiert vor 4 Jahren, 9 Monaten von Stanislav.
-
AutorBeiträge
-
Die nachfolgende Aufgabe werden wir im Crashkurs bearbeiten.
Du findest die Angabe auch in dieser PDF-Datei.
Unkommentierte Lösungen gibt es hier.Geben Sie unter Betrachtung des nachfolgenden Codes an, welche Ausgaben die in der main-Methode markierten Aufrufe produzieren. Sollte einer der Aufrufe nicht kompilieren oder zu einem Laufzeitfehler führen, so erklären Sie, welcher Fehler warum und an welcher Stelle auftritt. Die Aufrufe sind isoliert zu betrachten, d. h. alle anderen Aufrufe seien jeweils auskommentiert.
public class BasicPoly { static void write(String s) { System.out.println(s); } static class A { void m(A a) { write("A.m(A)"); a.m((B)a); } void m(B b) { write("A.m(B)"); this.m((A)b); } } static class B extends A { void m(B b) { write("B.m(B)"); } void m(C c) { write("B.m(C)"); this.m(this); c.m(this); } } static class C extends A { void m(A a) { write("C.m(A)"); } A m(D d) { write("C.m(D)"); return d; } } static class D extends B { void m(A a) { write("D.m(A)"); } void m(B b) { write("D.m(B)"); b.m(new B()); } void m(C c) { write("D.m(C)"); c.m(c); super.m(c); } } public static void main(String[] args) { B b = new B(); C c = new C(); D d = new D(); A x = b; A z = d; z.m(c); // Aufruf 1 x.m(d); // Aufruf 2 ((A)c).m(x); // Aufruf 3 c.m(b); // Aufruf 4 x.m(x); // Aufruf 5 z.m(b); // Aufruf 6 new A().m(b); // Aufruf 7 x.m(c); // Aufruf 8 z.m(d); // Aufruf 9 b.m(c); // Aufruf 10 ((B)c).m(x); // Aufruf 11 x.m(z); // Aufruf 12 b.m(a); // Aufruf 13 d.m(c); // Aufruf 14 c.m(c.m(d)); // Aufruf 15 c.m(d).m(c); // Aufruf 16 c.m(d).m(c.m(d)); // Aufruf 17 } }
- Dieses Thema wurde geändert vor 4 Jahren, 10 Monaten von Stefan Berktold.
- Dieses Thema wurde geändert vor 4 Jahren, 10 Monaten von Stefan Berktold.
- Dieses Thema wurde geändert vor 4 Jahren, 10 Monaten von Stefan Berktold.
Zusatzaufgabe: Polymorphie mit Attributen
Die Java-Dateien der Polymorphie-Aufgaben aus dem Crashkurs findest du hier.
Die unkommentierte Lösung zu dieser Aufgabe findest du hier, ein Objektdiagramm hier.public class AttributPoly { static class A { protected B a; public A() { a = new C(this); } public A(B b) { set(b); } public void set(B b) { a = b; } void f(B b) { System.out.println("A.f(B)"); a.f(this); } } static class B extends A { public B(B b) { super(b); } public B() { } void f(A a) { System.out.println("B.f(A)"); this.a.f(a); } void f(B b) { System.out.println("B.f(B)"); } } static class C extends B { private A a; public C(A a) { super(null); this.a = a; } void f(A a) { System.out.println("C.f(A)"); } void f(B b) { System.out.println("C.f(B)"); a.f(this); } void f(C c) { System.out.println("C.f(C)"); } } public static void main(String[] args) { B b = new B(); A a = new A(); B c = a.a; c.set(b); b.a.set(c); b.f(a); // Aufruf 1 c.f((C)c); // Aufruf 2 a.f(a); // Aufruf 3 b.a.f(c); // Aufruf 4 a.f(b); // Aufruf 5 ((C)c).a.f(c); // Aufruf 6 ((C) a.a.a.a).a.a.a.f(a); // Aufruf 7 } }
Zusatzaufgabe: Polymorphie mit parametrisierten Klassen (Generics)
Die Java-Dateien der Polymorphie-Aufgaben aus dem Crashkurs findest du hier.
Die unkommentierte Lösung zu dieser Aufgabe findest du hier, ein Objektdiagramm hier.public class GenericPoly { static class A<T extends B> { protected T e; public void set(T elem) { e = elem; } void f(B b) { System.out.println("A.f(B)"); } void f(C<E> c) { System.out.println("A.f(C)"); e.f(e); c.f(e); } void g(F f) { System.out.println("A.g(F)"); } } static class B extends A<B> { public B() { set(this); } void f(C<E> c) { System.out.println("B.f(C)"); } void f(F f) { System.out.println("B.f(F)"); this.g(f); } } static class C<R extends E> extends B { public R e; public C(R r) { this.e = r; } void f(B b) { System.out.println("C.f(B)"); } void f(A<C<E>> a) { System.out.println("C.f(A)"); a.f(this); } void g(F f) { System.out.println("C.g(F)"); e.g(f); } } static class D extends A<C<E>> implements E { protected A<B> e; public D() { e = new C<D>(this); } public void f(D d) { System.out.println("D.f(D)"); e.f(super.e); } public void g(F f) { System.out.println("D.g(F)"); } public void g(E e) { System.out.println("D.g(E)"); } } interface E { void g(E e); } static class F extends D { void f(A<C<F>> a) { System.out.println("F.f(A)"); this.f(a.e); } public void f(D d) { System.out.println("F.f(D)"); super.f(this); } } public static void main(String[] args) { A<C<F>> a = new A<>(); C<F> c = new C<>(new F()); a.set(c); D d = c.e; d.f(c); // Aufruf 1 c.f(a.e); // Aufruf 2 d.f(a); // Aufruf 3 d.f(d); // Aufruf 4 c.f(d); // Aufruf 5 d.e.f(c); // Aufruf 6 ((F)d).f(a); // Aufruf 7 c.f((F)d); // Aufruf 8 a.f(((A<C<E>>)d).e); // Aufruf 9 } }
LinaAttributParty:
Bei Aufruf 2) wähle ich Methode f(B) in Klasse C also C.f(B). Darauf folgt der Aufruf a.f(this). Hier finde ich in der Klasse A den Aufruf A.f(B). Wieso nehme ich dann diese Methode und nicht die Methode C.f(B) aus C? A müsste doch dynamisch C sein da ich es auf einem C aufgerufen habe?
Es geht um den Aufruf
a.f(this)
:a
ist dynamisch nichtC
sondernA
!this
ist statischC
, weil wir in der Klasse C sind, und dynamisch ebenfalls C, weil beim vorherigen Aufruf (c.f((C)c)
) ein C-Objekt vor dem Punkt stand, d. h. wir operieren auf einem C-Objekt.- Nachdem wir also auf einem C-Objekt operieren, handelt es sich bei
a
um das Attributa
des C-Objekts, das ursprünglich durchA a = new A()
innerhalb des A-Kontruktors mitnew C(this)
erzeugt wurde . Dort wirdthis
(also während der Erzeugung von A das A-Objekt selbst) übergeben. Das C-Objekt speichert sich genau dieses A-Objekt in seinem Attributa
ab (mittelsthis.a = a
), d. h. das hier verwendetea
hat den dynamischen Typ A (und zwar genau das A-Objekt, das auch in dermain
-Methode gespeichert wird).
Daher suchen wir in A eine Methode f(C), finden statisch f(B) und führen diese Methode auch aus.
StanislavHallo Stefan, kannst du uns erklären, warum wir bei der dritten Übung (GenericPoly) durch Aufruf 8 nach B.f(F)->C.g(F) D.g(E) und nicht D.g(F) drucken.
Und zweitens, wenn wir ein Attribut von einem Objekt aufrufen, das mehrere Attribute mit demselben Namen hat (von denen einige aus den oberen Klassen stammen), wie wählen wir dann aus, welches wir nehmen? Ich meine, wählen wir immer das Attribut, das von der Klasse selbst kommt? Ich beziehe mich auf die zweite Übung (AttributPoly), den 4-sten Aufruf (zweiten Call im Aufruf -> a.f(this) ).Vielen Dank !
Der Aufruf 8 kommt ja irgendwann zu
e.g(f)
. Der statische Typ vone
ist hier jedoch nichtF
sondernE
. Grund dafür ist Type Erasure, weil der Aufruf innerhalb vonC<?>
stattfindet. Der Compiler weiß nicht, dass wir hier fix inC<F>
sind (wir könnten irgendwann ja auch mal inC<D>
sein). Der statische Typ muss für einen bestimmten Kontext aber immer fix sein. Deshalb wird füre
der allgemeinste mögliche Typ genommen und das istE
(wegenC<R extends E>
). Dann suchen wirg(F)
inE
, finden dortg(E)
und überschreiben es anschließend inF
.Das Attribut bestimmten wir immer über den statischen Typ, also den Typ der Variable, von der wir auf ein Attribut zugreifen bzw. von der Klasse, in der wir uns befinden. Bei
d.e
ist der statische Typ vond
bspw.D
(dynamischF
), also wollen wir imF
-Objekt die Variablee
. Dort gibt es zwei, weilF
dase
Attribut ausD
undA
erbt. Wir wählen das ausD
geerbtee
, weil der statische Typ vond
D
ist, also besteht nur Zugriff auf die Variablen ausD
und Oberklassen vonD
.StanislavHey Stefan,Es geht um die Aufgabe Attributpoly – da vergleiche ich den 2en und 4en Aufruf. Im zweiten Aufuruf bei zweiten Call (a.f(this) sollen wir als statyscher Typ für a im C den statyschien Typ von c (was B ist) nehmen, weil wir von c den Call machen ? Das hab ich zumindest verstaden von deiner letzten Erklärung. Aber in Lösungen steht, dass wir in C die a mit statysh A nemhen. Aber im 4ten Aufruf funktioniert deine Logik und da wählen wir die a in C mit statytisch B, weil wir von b kommen.
Ich hoffe du hast mir verstanden. Kannst du bitte erklären oder einfach genau die 2 Aufrufe schriftlich bzw. mit einem Diagramm zeigen. Danke !
-
AutorBeiträge