interface A {
void methodToImplement();
static void someStaticMethod() {
/* code inside */
}
}
...
A.someStaticMethod();
Tomáš Pitner, Radek Ošlejšek, Marek Šabo
Jde o možnosti, jak do rozhraní přímo implementovat funkčnost, nenechávat to až na třídy.
Popírá základní princip, že v rozhraní funkční kód metod není.
⇒ má omezené použití a nemělo by se zneužívat
Existují dva základní typy metod:
statické — static
výchozí — default
Rozhraní může obsahovat statické metody.
Statické metody smějí pracovat jen s dalšími statickými metodami a proměnnými.
Nesmějí pracovat s metodami a atributy objektu.
interface A {
void methodToImplement();
static void someStaticMethod() {
/* code inside */
}
}
...
A.someStaticMethod();
Nechť existuje rozhraní, které implementuje 10 tříd.
Do rozhraní chceme přidat novou metodu.
Metoda musí být (bohužel) implementována ve všech rozhraních!
Co kdyby rozhraní poskytovalo i svou výchozí implementaci, kterou by třídy nemuseli implementovat?
výchozí = default
Oracle The Java Tutorial: Default Methods |
Výchozí metodu můžeme samozřejmě ve třídách překrýt.
interface Addressable {
String getStreet();
String getCity();
default String getFullAddress() {
return getStreet() +", " + getCity();
}
}
Výchozí metody používáme, když chceme:
přidat novou metodu do existujícího rozhraní
všechny třídy implementující rozhraní pak nemusí implementovat novou metodu
nahradit abstraktní třídu za rozhraní
abstraktní třída vynucuje dědičnost
preferujeme implementaci rozhraní před dědičností tříd
Statické metody se mohou v rozhraní využít při psaní výchozích metod:
interface A {
static void someStaticMethod() {
/* some stuff */
}
default void someMethod() {
// can call static method
someStaticMethod();
}
}
Mějme rozhraní A
obsahující výchozí metodu defaultMethod()
.
Definujme-li rozhraní B
jako rozšíření rozhraní A
, mohou nastat 3 různé situace:
Jestliže výchozí metodu defaultMethod()
v rozhraní B
nezmiňujeme, pak se podědí z A
.
V rozhraní B
uvedeme metodu defaultMethod()
, 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.
V rozhraní B
implementujeme metodu znovu,
čímž se původní výchozí metoda překryje — jako při dědění mezi třídami.
Následující kód se nezkompiluje:
interface A {
default void someMethod() { /*bla bla*/ }
}
interface B {
default void someMethod() { /*bla bla*/ }
}
class C implements A, B {
// compiler does not know which default method should be used
}
Následující kód je zkompiluje:
interface A {
default void someMethod() { /*bla bla*/ }
}
interface B {
default void someMethod() { /*bla bla*/ }
}
class D implements A, B {
@Override
public void someMethod() {
// now we can define the behaviour
A.super.someMethod();
}
}
Následující kód se opět nezkompiluje.
Jedno rozhraní default metodu má a druhé ne.
interface A { void someMethod(); }
interface B { default void someMethod() { /* whatever */ } }
class E implements A, B {
// compiler should or should not use default method?
}