Crashkurs-Aufgaben zu Polymorphie

EIDI-Crashkurs 2020 Crashkurs-Aufgaben zu Polymorphie

Ansicht von 8 Beiträgen - 1 bis 8 (von insgesamt 8)
  • Autor
    Beiträge
  • #2849 Antworten

    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
       }
    }
    

    #3188 Antworten

    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
       }
    }
    

    #3189 Antworten

    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
       }
    }
    

    #3245 Antworten
    Lina

    AttributParty: 

    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? 

    #3247 Antworten

    Es geht um den Aufruf a.f(this): a ist dynamisch nicht C sondern A!

    • thisist statisch C, 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 Attribut a des C-Objekts, das ursprünglich durch A a = new A() innerhalb des A-Kontruktors mit new C(this) erzeugt wurde . Dort wird this (also während der Erzeugung von A das A-Objekt selbst) übergeben. Das C-Objekt speichert sich genau dieses A-Objekt in seinem Attribut a ab (mittels this.a = a), d. h. das hier verwendete a hat den dynamischen Typ A (und zwar genau das A-Objekt, das auch in der main-Methode gespeichert wird).

    Daher suchen wir in A eine Methode f(C), finden statisch f(B) und führen diese Methode auch aus.

    #3412 Antworten
    Stanislav

    Hallo 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 !

     

     

    #3421 Antworten

    Der Aufruf 8 kommt ja irgendwann zu e.g(f). Der statische Typ von e ist hier jedoch nicht F sondern E. Grund dafür ist Type Erasure, weil der Aufruf innerhalb von C<?> stattfindet. Der Compiler weiß nicht, dass wir hier fix in C<F> sind (wir könnten irgendwann ja auch mal in C<D> sein). Der statische Typ muss für einen bestimmten Kontext aber immer fix sein. Deshalb wird für e der allgemeinste mögliche Typ genommen und das ist E (wegen C<R extends E>). Dann suchen wir g(F) in E, finden dort g(E) und überschreiben es anschließend in F.

    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 von d bspw. D (dynamisch F), also wollen wir im F-Objekt die Variable e. Dort gibt es zwei, weil F das e Attribut aus D und A erbt. Wir wählen das aus D geerbte e, weil der statische Typ von d D ist, also besteht nur Zugriff auf die Variablen aus D und Oberklassen von D.

    #3512 Antworten
    Stanislav

    Hey 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 ! 

Ansicht von 8 Beiträgen - 1 bis 8 (von insgesamt 8)
Antwort auf: Crashkurs-Aufgaben zu Polymorphie

Deine Nachricht und Pseudonym (Name) sind für alle einsehbar (Datenschutz).

Deine Information: