Skip to content

Latest commit

 

History

History
372 lines (284 loc) · 11.6 KB

defaultmethods.md

File metadata and controls

372 lines (284 loc) · 11.6 KB
archetype title linkTitle author readings tldr outcomes quizzes youtube fhmedia challenges
lecture-cg
Interfaces: Default-Methoden
Default-Methoden
Carsten Gips (HSBI)
key comment
Java-SE-tutorial
Learning the Java Language: Interfaces and Inheritance: Abschnitt Default Methods
key comment
Urma2014
Kapitel 9: Default Methods
Seit Java8 können Methoden in Interfaces auch fertig implementiert sein: Sogenannte **Default-Methoden**. Dazu werden die Methoden mit dem neuen Schlüsselwort `default` gekennzeichnet. Die Implementierung wird an die das Interface implementierenden Klassen (oder Interfaces) vererbt und kann bei Bedarf überschrieben werden. Da eine Klasse von einer anderen Klasse erben darf, aber mehrere Interfaces implementieren kann, könnte es zu einer Mehrfachvererbung einer Methode kommen: Eine Methode könnte beispielsweise in verschiedenen Interfaces als Default-Methode angeboten werden, und wenn eine Klasse diese Interfaces implementiert, steht eine Methode mit der selben Signatur auf einmal mehrfach zur Verfügung. Dies muss (u.U. manuell) aufgelöst werden. Auflösung von Mehrfachvererbung: * Regel 1: Klassen gewinnen * Regel 2: Sub-Interfaces gewinnen * Regel 3: Methode explizit auswählen Aktuell ist der Unterschied zu abstrakten Klassen: Interfaces können **keinen Zustand** haben, d.h. keine Attribute/Felder.
k2
Interfaces mit Default-Methoden, Unterschied zu abstrakten Klassen
k2
Problem der Mehrfachvererbung
k3
Erstellen von Interfaces mit Default-Methoden
k3
Regeln zum Auflösen der Mehrfachvererbung
link name
VL Default-Methoden
link name
Demo Regel 1
link name
Demo Regel 2
link name
Demo Regel 3
Erklären Sie die Code-Schnipsel in der [Vorgabe](https://github.com/Programmiermethoden-CampusMinden/Prog2-Lecture/tree/master/lecture/modern-java/src/challenges/defaults) und die jeweils entstehenden Ausgaben. <!-- ``` new Voegel.Schornsteinsegler().gleiten(); "Sub-Interfaces gewinnen" new Enten.Ente().fortbewegen(); "Methode explizit auswählen" new Pinguine.Kaiserpinguin().schwimmen(); "Sub-Interfaces gewinnen" da Pinguin nicht die Methode implementiert. new Kolibris.Adlerschnabel().schweben(); "Klassen gewinnen" ``` -->

Problem: Etablierte API (Interfaces) erweitern

interface Klausur {
    void anmelden(Studi s);
    void abmelden(Studi s);
}

\bigskip \pause

=> Nachträglich noch void schreiben(Studi s); ergänzen?

::: notes Wenn ein Interface nachträglich erweitert wird, müssen alle Kunden (also alle Klassen, die das Interface implementieren) auf die neuen Signaturen angepasst werden. Dies kann viel Aufwand verursachen und API-Änderungen damit unmöglich machen. :::

Default-Methoden: Interfaces mit Implementierung

::: notes Seit Java8 können Interfaces auch Methoden implementieren. Es gibt zwei Varianten: Default-Methoden und statische Methoden. :::

interface Klausur {
    void anmelden(Studi s);
    void abmelden(Studi s);

    default void schreiben(Studi s) {
        ...     // Default-Implementierung
    }

    default void wuppie() {
        throw new java.lang.UnsupportedOperationException();
    }
}

::: notes Methoden können in Interfaces seit Java8 implementiert werden. Für Default-Methoden muss das Schlüsselwort default vor die Signatur gesetzt werden. Klassen, die das Interface implementieren, können diese Default-Implementierung erben oder selbst neu implementieren (überschreiben). Alternativ kann die Klasse eine Default-Methode neu deklarieren und wird damit zur abstrakten Klasse.

Dies ähnelt abstrakten Klassen. Allerdings kann in abstrakten Klassen neben dem Verhalten (implementierten Methoden) auch Zustand über die Attribute gespeichert werden. :::

::: notes

Problem: Mehrfachvererbung

Drei Regeln zum Auflösen bei Konflikten:

  1. Klassen gewinnen: Methoden aus Klasse oder Superklasse haben höhere Priorität als Default-Methoden
  2. Sub-Interfaces gewinnen: Methode aus am meisten spezialisiertem Interface mit Default-Methode wird gewählt Beispiel: Wenn B extends A dann ist B spezialisierter als A
  3. Sonst: Klasse muss Methode explizit auswählen: Methode überschreiben und gewünschte (geerbte) Variante aufrufen: X.super.m(...) (X ist das gewünschte Interface)

Auf den folgenden Folien wird dies anhand kleiner Beispiele verdeutlicht. :::

[[Hinweis: Mehrfachvererbung]{.bsp}]{.slides}

Auflösung Mehrfachvererbung: 1. Klassen gewinnen

interface A {
    default String hello() { return "A"; }
}
class C {
    public String hello() { return "C"; }
}
class E extends C implements A {}


/** Mehrfachvererbung: 1. Klassen gewinnen */
public class DefaultTest1 {
    public static void main(String... args) {
        String e = new E().hello();
    }
}

[Demo: defaultmethods.rule1.DefaultTest1]{.bsp href="https://github.com/Programmiermethoden-CampusMinden/Prog2-Lecture/blob/master/lecture/modern-java/src/defaultmethods/rule1/DefaultTest1.java"}

::: notes Die Klasse E erbt sowohl von Klasse C als auch vom Interface A die Methode hello() (Mehrfachvererbung). In diesem Fall "gewinnt" die Implementierung aus Klasse C.

1. Regel: Klassen gewinnen immer. Deklarationen einer Methode in einer Klasse oder einer Oberklasse haben Vorrang von allen Default-Methoden. :::

Auflösung Mehrfachvererbung: 2. Sub-Interfaces gewinnen

interface A {
    default String hello() { return "A"; }
}
interface B extends A {
    @Override default String hello() { return "B"; }
}
class D implements A, B {}


/** Mehrfachvererbung: 2. Sub-Interfaces gewinnen */
public class DefaultTest2 {
    public static void main(String... args) {
        String e = new D().hello();
    }
}

[Demo: defaultmethods.rule2.DefaultTest2]{.bsp href="https://github.com/Programmiermethoden-CampusMinden/Prog2-Lecture/blob/master/lecture/modern-java/src/defaultmethods/rule2/DefaultTest2.java"}

::: notes Die Klasse D erbt sowohl vom Interface A als auch vom Interface B die Methode hello() (Mehrfachvererbung). In diesem Fall "gewinnt" die Implementierung aus Klasse B: Interface B ist spezialisierter als A.

2. Regel: Falls Regel 1 nicht zutrifft, gewinnt die Default-Methode, die am meisten spezialisiert ist. :::

Auflösung Mehrfachvererbung: 3. Methode explizit auswählen

interface A {
    default String hello() { return "A"; }
}
interface B {
    default String hello() { return "B"; }
}
class D implements A, B {
    @Override public String hello() { return A.super.hello(); }
}


/** Mehrfachvererbung: 3. Methode explizit auswählen */
public class DefaultTest3 {
    public static void main(String... args) {
        String e = new D().hello();
    }
}

[Demo: defaultmethods.rule3.DefaultTest3]{.bsp href="https://github.com/Programmiermethoden-CampusMinden/Prog2-Lecture/blob/master/lecture/modern-java/src/defaultmethods/rule3/DefaultTest3.java"}

::: notes Die Klasse D erbt sowohl vom Interface A als auch vom Interface B die Methode hello() (Mehrfachvererbung). In diesem Fall muss zur Auflösung die Methode in D neu implementiert werden und die gewünschte geerbte Methode explizit aufgerufen werden. (Wenn dies unterlassen wird, führt das selbst bei Nicht-Nutzung der Methode hello() zu einem Compiler-Fehler!)

Achtung: Der Aufruf der Default-Methode aus Interface A erfolgt mit A.super.hello(); (nicht einfach durch A.hello();)!

3. Regel: Falls weder Regel 1 noch 2 zutreffen bzw. die Auflösung noch uneindeutig ist, muss man manuell durch die explizite Angabe der gewünschten Methode auflösen. :::

Quiz: Was kommt hier raus?

interface A {
    default String hello() { return "A"; }
}
interface B extends A {
    @Override default String hello() { return "B"; }
}
class C implements B {
    @Override public String hello() { return "C"; }
}
class D extends C implements A, B {}


/** Quiz Mehrfachvererbung */
public class DefaultTest {
    public static void main(String... args) {
        String e = new D().hello(); // ???
    }
}

::: notes Die Klasse D erbt sowohl von Klasse C als auch von den Interfaces A und B die Methode hello() (Mehrfachvererbung). In diesem Fall "gewinnt" die Implementierung aus Klasse C: Klassen gewinnen immer (Regel 1).

[Beispiel: defaultmethods.quiz.DefaultTest]{.bsp href="https://github.com/Programmiermethoden-CampusMinden/Prog2-Lecture/blob/master/lecture/modern-java/src/defaultmethods/quiz/DefaultTest.java"} :::

::: notes

Statische Methoden in Interfaces

public interface Collection<E> extends Iterable<E> {
    boolean add(E e);
    ...
}
public class Collections {
    private Collections() { }
    public static <T> boolean addAll(Collection<? super T> c, T... elements) {...}
    ...
}

Typisches Pattern in Java: Interface plus Utility-Klasse (Companion-Klasse) mit statischen Hilfsmethoden zum einfacheren Umgang mit Instanzen des Interfaces (mit Objekten, deren Klasse das Interface implementiert). Beispiel: Collections ist eine Hilfs-Klasse zum Umgang mit Collection-Objekten.

Seit Java8 können in Interfaces neben Default-Methoden auch statische Methoden implementiert werden.

Die Hilfsmethoden können jetzt ins Interface wandern => Utility-Klassen werden obsolet ... Aus Kompatibilitätsgründen würde man die bisherige Companion-Klasse weiterhin anbieten, wobei die Implementierungen auf die statischen Methoden im Interface verweisen (SKIZZE, nicht real!):

public interface CollectionX<E> extends Iterable<E> {
    boolean add(E e);
    static <T> boolean addAll(CollectionX<? super T> c, T... elements) { ... }
    ...
}
public class CollectionsX {
    public static <T> boolean addAll(CollectionX<? super T> c, T... elements) {
        return CollectionX.addAll(c, elements);  // Verweis auf Interface
    }
    ...
}

:::

Interfaces vs. Abstrakte Klassen

  • Abstrakte Klassen: Schnittstelle und Verhalten und Zustand

  • Interfaces:

    • vor Java 8 nur Schnittstelle
    • ab Java 8 Schnittstelle und Verhalten

    ::: notes Unterschied zu abstrakten Klassen: Kein Zustand, d.h. keine Attribute :::

\bigskip

  • Design:
    • Interfaces sind beinahe wie abstrakte Klassen, nur ohne Zustand
    • Klassen können nur von einer (abstrakten) Klasse erben, aber viele Interfaces implementieren

Wrap-Up

Seit Java8: Interfaces mit Implementierung: Default-Methoden

\bigskip

  • Methoden mit dem Schlüsselwort default können Implementierung im Interface haben
  • Die Implementierung wird vererbt und kann bei Bedarf überschrieben werden
  • Auflösung von Mehrfachvererbung:
    • Regel 1: Klassen gewinnen
    • Regel 2: Sub-Interfaces gewinnen
    • Regel 3: Methode explizit auswählen
  • Unterschied zu abstrakten Klassen: Kein Zustand

::: slides

LICENSE

Unless otherwise noted, this work is licensed under CC BY-SA 4.0. :::