Site icon Java blog

Java 8 #1: metody domyślne i statyczne w interfejsach

java 8 interface

Interfejsy w JDK 7

Zanim zacznę opisywać zmiany jakie zaszły w interfejsach w Javie w wersji ósmej, takie jak np. metody domyślne czy metody statyczne, spójrz na moje małe podsumowanie, jak działały one w poprzedniej wersji.

Właściwości interfejsów w JDK 7:

Metody statyczne

Nie ma tu wielkiej filozofii. Po prostu od teraz możesz pisać publiczne metody statyczne w swoim interfejsie. Nie łamie to idei interfejsu (czyli bezstanowości), ponieważ metoda statyczna należy do klasy (w tym przypadku interfejsu) a nie do obiektu (instancji).

Przykładowy interfejs zawierający stałą, jedną sygnaturę i metodę statyczną.

public interface Flying {
	public static final String NAME = "Flying interface";
	
	public void fly();
	public static boolean isAllowToFly(String weather) {
		return "good".equals(weather) ? true : false;
	}
}

Metody domyślnie

Kolejną nowością w Javie 8 są metody domyślne. Przypominają one powyższe metody statyczne, tzn. po zaimplementowaniu interfejsu w swojej klasie, możesz odwoływać się do tej metody. Ważna różnica pomiędzy nimi, jest to, że metody domyślne tak jak każde metody instancyjne (niestatyczne) można nadpisywać. Najprościej metody domyślne można rozumieć jako podstawową implementację danej sygnatury, zawartej już w samym interfejsie.

public interface Flying {
	public static final String NAME = "Flying interface";
	
	public void fly();
	public static boolean isAllowToFly(String weather) {
		return "good".equals(weather) ? true : false;
	}
	
	default void showName(){  
        System.out.println(NAME);  
    } 
}

Przykład klasy, która nadpisuje domyślną metodę showname.

public class Plane implements Flying{

	@Override
	public void fly() {
		System.out.println("fly..");
	}
	
	@Override
	public void showName(){  
		System.out.println("Show plane"); 
    }
}

Pewnym problemem wynikającym z posiadania metod domyślnych może być posiadanie konfliktów przy używania tych samych nazw w różnych interfejsach.

public interface Landing {
	public static final String NAME = "Landing interface";
	
	public void land();
	
	default void showName(){  
        System.out.println(NAME);  
    } 
}

Mój nowy interfejs posiada tą samą metodę domyślną jak interfejs Flying. Co się stanie w przypadku implementacji obu interfejsów w tej samej klasie? W takim przypadku kompilator zgłosi błąd:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
	Duplicate default methods named showName with the parameters () and () are inherited from the types Landing and Flying

Tego typu problem nazywa się problemem diamentu (ang. diamond problem*). Aby go obejść można nadpisać skonfliktowaną metodę i w jej ciele wybrać, którą implementację wybierasz.

public class PlaneConflict implements Flying, Landing{

	@Override
	public void land() {}

	@Override
	public void fly() {}

	@Override
	public void showName() {
		Flying.super.showName();
	}
}

Interfejsy funkcyjne

Metody domyślne i statyczne to nie jedyne zmiany jakie zaszły w interfejsach. Ostatnią ciekawą kwestią dodaną do JDK 8 jest możliwość tworzenia interfejsów funkcyjnych, ale ten temat omówię już w kolejnej lekcji.

* https://en.wikipedia.org/wiki/Multiple_inheritance

Kod do lekcji: https://github.com/developeronthego/java-jdk8/tree/master/src/main/java/java8/interfaces

Przypomnienie jak działają interfejsy: Java #27: implementacja interfejsu

Exit mobile version