// Quiz.java

/**
 * Quiz zu statischer und dynamischer Bindung.
 * - In welchen Zeilen werden welche Methoden der Klassen A und B aufgerufen?
 * - Wo werden die Methodenaufrufe statische gebunden und wo dynamisch?
 * Beispielprogramm zur Programmiertechnik 1, Teil 5.
 * @author H.Drachenfels
 * @version 29.6.2020
 */

public final class Quiz {
    private Quiz() { }

    /**
     * main versucht auf verschiedenen Wegen,
     * die Methoden der Klassen A und B aufzurufen.
     * @param args wird nicht verwendet
     */
    public static void main(String[] args) {
        System.out.printf(
            "%n# Aufrufe mit Klassenname A:%n");
        A.f();  // ok, kein Parameter this bei static-Methoden
      //A.g();  // Fehler, Parameter this kann nicht initialisiert werden
      //A.h();  // Fehler, Parameter this kann nicht initialisiert werden
      //A.i();  // Fehler wegen private und this

        System.out.printf(
            "%n# Aufrufe mit Variabler vom Typ A und Objekt der Klasse A:%n");
        A a = new A();  // statische Bindung: A.A(a)
        a.f();  // statische Bindung: A.f(), kein Parameter this
        a.g();  // dynamische Bindung: A.g(a)
        a.h();  // dynamische Bindung: A.h(a)
      //a.i();  // Fehler wegen private

        System.out.printf(
            "%n# Aufrufe mit Variabler vom Typ A und Objekt der Klasse B:%n");
        a = new B(); // statische Bindung: A.A(a) B.B(a), a polymorph
        a.f();  // statische Bindung: A.f(), kein Parameter this
        a.g();  // dynamische Bindung: A.g(a)
        a.h();  // dynamische Bindung: B.h(a)
      //a.i();  // Fehler wegen private

        System.out.printf(
            "%n# Aufrufe mit Variabler vom Typ B und Objekt der Klasse B:%n");
        B b = new B();  // statische Bindung: A.A(b) B.B(b)
        b.f();  // statische Bindung: B.f(), kein Parameter this
        b.g();  // dynamische Bindung: A.g(b)
        b.h();  // dynamische Bindung: B.h(b)
        b.i();  // dynamische Bindung: B.i(b)
    }
}

// Oberklasse A
class A {
    public A() {
        System.out.printf("A.A(%s)%n", this);
    }

    public static void f() {
        System.out.printf("A.f()%n");
    }

    public final void g() {
        System.out.printf("A.g(%s)%n", this);
    }

    public void h() {
        System.out.printf("A.h(%s)%n", this);
        this.i(); // statische Bindung: A.i(this)
    }

    private void i() {
        System.out.printf("A.i(%s)%n", this);
    }
}

// Unterklasse B von A
class B extends A {
    public B() {
        System.out.printf("B.B(%s)%n", this);
    }

    public static void f() {
        System.out.printf("B.f()%n");
    }

  //public void g() { } // Fehler wegen final in Oberklasse

    public void h() {
        System.out.printf("B.h(%s)%n", this);
        this.i();  // dynamische Bindung: B.i(this)
        super.h(); // statische Bindung: A.h(this)
    }

    public void i() {
        System.out.printf("B.i(%s)%n", this);
    }
}

