Java 8 Default Methoden

Die neueste Java Version, Java 8, wurde von Oracle endlich veröffentlicht. Nun stellt sich nicht nur die Frage, welche sprachlichen Erneuerungen es in Java 8 gibt, sondern auch wie diese anzuwenden sind. Im Internet kursieren deshalb viele verschiedene Artikel oder Tutorials, wovon die meisten eher kompliziert und deshalb schwer zu verstehen sind. Als der Erste einer ganzen Reihe von Artikeln zu Java 8, soll dieser hier auf einfache Art und Weise, die neuen Erweiterungen, welche Java 8 mit sich bringt, erläutern und anhand von Codebeispielen aufzeigen wie diese sinnvoll anzuwenden sind.

Implementierung

Als interessante Spracherweiterung der JDK 8 haben sich Default Methoden herausgestellt. Diese werden auch „Virtual Extension Methods“ oder „Defender Methods“ genannt. Sie erweitern ein Interface um Methoden, welche alle implementierenden Klassen automatisch erben, ohne dass diese Klassen geändert werden müssen. Default Methoden sind also ein „Standardverhalten“ für Klassen. Das folgende Beispiel soll das Deklarieren einer Default Methode verdeutlichen.

public interface Vehicle {
    public long km();
    public int gas();
    public default int brake() {
        return 2;
    }
}

Wie erkennbar ist, wird eine Default Methode mit dem Keyword „default“ deklariert und im Interface bereits implementiert. Die Implementierung jenes Interfaces ist in folgender Klasse Car ersichtlich.

public class Car implements Vehicle {
    @Override
    public long km() {
        return 25000l; // 25.000km
    }

    @Override
    public int gas() {
        return 2;
    }
}

Wie sich zeigt, ist in dieser Klasse Car keine Implementierung der brake() Methode von Nöten, da diese bereits im Interface Vehicle implementiert wurde und somit ein Standardverhalten für die Klasse darstellt. Der Aufruf der einzelnen Methoden jener Klasse geschieht auf herkömmliche Weise.

Vehicle car = new Car();
System.out.println(car.km()); // 25000
System.out.println(car.gas()); // 2
System.out.println(car.brake()); // 2

Problem

Leider wird durch Default Methoden eine Art von „Mehrfachvererbung“ (Multiple Inheritance) eingeführt. Dies geschieht zwangsläufig, sobald mehrere Methoden mit gleichem Namen in unterschiedlichen Typen definiert worden sind.  Im Falle der Vererbung mittels einer Klasse mit einer Methode und eines Interfaces mit gleichnamiger Default Methode, löst der Kompiler das Problem selbstständig auf, indem dieser die Methode der Klasse referenziert. Sobald jedoch zwei Interfaces, mit gleicher Default Methode in einer Klasse implementiert werden, kann der Kompiler nicht selbstständig eine Methode auswählen, da dieser klarerweise nicht weiß, welche Methode der Programmierer referenzieren will. Um dieses Problem zu verdeutlichen, wird ein Interface Tuneable, wie zuvor schon bei Vehicle, mit einer Default Methode brake(), implementiert.

public interface Tuneable {
    public default int brake() {
        return 4;
    }
}

Nun werden das Interface Vehicle und Tuneable in einer Klasse TuneableCar implementiert.

// WILL FAIL
public class TuneableCar implements Vehicle, Tuneable {
    @Override
    public long km() {
        return 25000l; // 25.000
    }

    @Override
    public int gas() {
        return 2;
    }
}

Der Kompiler wird in diesem Beispiel einen Fehler werfen, da, wie bereits erwähnt, zwei Default Methoden mit gleichen Namen benutzbar wären, dieser aber nicht weiß, welche er benutzen soll. Folgender Fehler wird ausgegeben werden.

java: class TuneableCar inherits unrelated defaults for brake() from types Vehicle and Tuneable

Lösungen

Dieses Problem sieht auf den ersten Blick vielleicht schwer lösbar aus, ist es jedoch keineswegs. Es gibt zwei verschiedene Lösungsansätze. Der einfachste Lösungsansatz ist jener, bei welchem die Default Methode in der implementierenden Klasse überschrieben und somit eine eigene Implementierung bereitgestellt wird.

public class TuneableCar implements Vehicle, Tuneable {
    // ...
    @Override
    public int brake() {
        return 2;
    }
}

Dieser Ansatz jedoch erlaubt es nicht, die Implementierung der Default Methode aus einem der Beiden Interfaces zu benutzen, da hier eine neue Implementierung bereitgestellt wird. Dieses Problem umgeht der zweite Lösungsansatz. Bei diesem wird die Default Methode ebenfalls in der implementierenden Klasse überschrieben, jedoch wird mittels super eine der beiden Default Methoden referenziert.

public class TuneableCar implements Vehicle, Tuneable {
    // ...    
    @Override
    public int brake() {
        return Tuneable.super.brake();
    }
}

Wie nun zu erkennen ist, ist dieses Problem der Mehrfachvererbung nichts dramatisches, da durch richtiges referenzieren der zu verwendenden Default Methode oder durch Vermeidung von gleichen Methodennamen, sich dieses Problem einfach lösen lässt oder es erst gar nicht entsteht. Generell kann man also feststellen, das trotz der erwähnten Schwierigkeiten, Default Methoden ein mächtiger Verbündeter sind, zum Beispiel um bereits bestehende Komponenten sinnvoll zu erweitern und somit nicht komplette Module einer Applikation umgeschrieben werden müssen.

Tagged with:     , ,

About the author /


Schon früh hat sich meine technische Begabung gezeigt, weshalb ich mich vor ein paar Jahren entschloss ein Informatik Studium zu beginnen. Ich beschäftige mich intensiv mit Programmieren, besonders im Bereich Java und Mobile Applications. Ich bin immer bemüht mich in verschiedensten technischen Bereichen weiterzubilden und neue Erfahrungen zu sammeln. Außerhalb der technischen Welt spiele ich gerne Squash, hin und wieder ein interessantes Computerspiel und ich versuche mich im Kochen und Backen mit mehr oder weniger gutem Erfolg.

Related Articles

Post your comments

Your email address will not be published. Required fields are marked *

*

Unterstütz uns!

Folgt uns!

Diese Seite

wurde erstellt mit Ehrgeiz, Liebe und viel Koffein. Bei der Erstellung kamen keine jar-Dateien zu Schaden. Das Logo wurde erstellt von Star-seven.at.