public interface Addressable { String getStreet(); String getCity(); default String getFullAddress() { return getStreet() +", " + getCity(); } }
default
)
static
)
default
a obsahují rovněž tělo (tj. implementaci) metody.
zdroj: Java SE 8’s New Language Features, Part 1: Interface Default/Static Methods and Lambda Expressions
public interface Addressable { String getStreet(); String getCity(); default String getFullAddress() { return getStreet() +", " + getCity(); } }
Dříve, bez výchozích metod, nebylo možné přidat v budoucí verzi rozhraní do něj metodu, aniž by se porušila binární kompatibilita se stávajícím kódem — všechny třídy implementující toto rozhraní by musely počínaje od nové verze implementovat i novou přidanou metodu, tudíž by stávající kód přestal fungovat.
Výchozí metody nás zbavují časté nutnosti použít abstraktní třídu pro implementaci obecných metod, které by se jinak ve (často všech) implementujících neabstraktních třídách opakovaly. Abstraktní třída pak návrháře nutí de facto nikoli k pouhé implementaci rozhraní, ale k dědění z takové abstraktní třídy, což narušuje javový koncept preferující implementaci rozhraní před dědičností.
interface A { static void someStaticMethod() { /* some stuff */ } default void someMethod() { // může zavolat statickou metodu someStaticMethod(); } }
A
obsahující nějakou výchozí metodu, třeba dm()
.
B
jako rozšíření (extends
) rozhraní A
,
mohou nastat tři různé situace:
dm()
v rozhraní B
nezmiňujeme, pak se podědí z A
.
B
uvedeme metodu dm()
, ale jen její hlavičku (ne tělo).
Pak ji nepodědíme, stane se abstraktní jako u každé obyčejné metody v rozhraní
a každá třída implementující rozhraní B
ji musí sama implementovat.
B
implementujeme metodu znovu,
čímž se původní výchozí metoda překryje — jako při dědění mezi třídami.
interface A { default void someMethod() { /*bla bla*/ } } interface B { default void someMethod() { /*bla bla*/ } } class C implements A, B { // překladač by nevěděl, kterou someMethod() použít }
interface A { default void someMethod() { /*bla bla*/ } } interface B { default void someMethod() { /*bla bla*/ } } class D implements A, B { // překryjeme-li (dvojitě) poděděnou metodu, není problém // překladač nemusí přemýšlet, someMethod() použít public void someMethod() { // the right stuff, this will be used } }
interface A { void someMethod(); } interface B { default void someMethod() { /* whatever */ } } class E implements A, B { // nepřeloží, protože zůstává otázka: // má či nemá překladač použít výchozí metodu? }