Różnica między klasą Abstact a interfejsem
- Klasy abstrakcyjne a interfejsy w Javie 8
- Różnica koncepcyjna:
Domyślne metody interfejsu w Javie 8
- Co to jest metoda domyślna?
- Błąd kompilacji metody ForEach rozwiązany przy użyciu metody domyślnej
- Metoda domyślna i problemy z wieloznacznością dziedziczenia wielokrotnego
- Ważne informacje na temat domyślnych metod interfejsu Java:
Metoda statyczna interfejsu Java
- Metoda statyczna interfejsu Java, przykład kodu, metoda statyczna a metoda domyślna
- Ważne informacje dotyczące statycznej metody interfejsu Java:
Interfejsy funkcjonalne Java
Klasy abstrakcyjne a interfejsy w Javie 8
Zmiany interfejsu Java 8 obejmują metody statyczne i metody domyślne w interfejsach. W wersjach wcześniejszych niż Java 8 w interfejsach mogliśmy mieć tylko deklaracje metod. Ale w Javie 8 możemy mieć domyślne interfejsy i metody statyczne w interfejsach.
Po wprowadzeniu metody domyślnej wydaje się, że interfejsy i klasy abstrakcyjne są takie same. Jednak nadal są one odmienną koncepcją w Javie 8.
Klasa abstrakcyjna może definiować konstruktor. Są bardziej ustrukturyzowane i mogą mieć z nimi skojarzony stan. Natomiast w przeciwieństwie do metody domyślnej można zaimplementować tylko w zakresie wywoływania innych metod interfejsu, bez odniesienia do stanu określonej implementacji. W związku z tym oba służą do różnych celów, a wybór między nimi naprawdę zależy od kontekstu scenariusza.
Różnica koncepcyjna:
Klasy abstrakcyjne są poprawne dla szkieletowych (tj. Częściowych) implementacji interfejsów, ale nie powinny istnieć bez pasującego interfejsu.
Więc kiedy klasy abstrakcyjne zostaną skutecznie zredukowane do niewidoczności, szkieletowe implementacje interfejsów, czy metody domyślne również to zabiorą? Zdecydowanie: nie! Implementacja interfejsów prawie zawsze wymaga niektórych lub wszystkich narzędzi do budowania klas, których brakuje metod domyślnych. A jeśli jakiś interfejs tego nie robi, jest to wyraźnie przypadek szczególny, który nie powinien cię sprowadzać na manowce.
Domyślne metody interfejsu w Javie 8
Java 8 wprowadza „ metodę domyślną nową funkcję ” lub (metody Defender), która pozwala programistom dodawać nowe metody do interfejsów bez przerywania istniejącej implementacji tych interfejsów. Zapewnia elastyczność umożliwiającą implementację interfejsu, która będzie domyślnie używana w sytuacji, gdy konkretna klasa nie zapewni implementacji dla tej metody.
Rozważmy mały przykład, aby zrozumieć, jak to działa:
public interface OldInterface {
public void existingMethod();
default public void newDefaultMethod() {
System.out.println("New default method"
+ " is added in interface");
}
}
Następująca klasa pomyślnie skompiluje się w Javie JDK 8,
public class OldInterfaceImpl implements OldInterface {
public void existingMethod() {
// existing implementation is here…
}
}
Jeśli utworzysz instancję OldInterfaceImpl:
OldInterfaceImpl obj = new OldInterfaceImpl ();
// print “New default method add in interface”
obj.newDefaultMethod();
Metody domyślne nigdy nie są ostateczne, nie mogą być synchronizowane i nie mogą zastępować metod Object. Są one zawsze publiczne, co poważnie ogranicza możliwość pisania krótkich metod wielokrotnego użytku.
Do interfejsu można podać domyślne metody bez wpływu na implementację klas, ponieważ obejmuje on implementację. Jeśli każda dodana metoda w interfejsie zdefiniowanym z implementacją nie wpłynie na żadną klasę implementującą. Klasa implementująca może zastąpić domyślną implementację zapewnianą przez interfejs.
Domyślne metody pozwalają dodawać nowe funkcje do istniejących interfejsów bez przerywania starszej implementacji tych interfejsów.
Po rozszerzeniu interfejsu zawierającego metodę domyślną możemy wykonać następujące czynności,
- Nie zastępuj metody domyślnej i odziedziczy metodę domyślną.
- Zastąp domyślną metodę podobną do innych metod, które zastępujemy w podklasie.
- Ponownie określ domyślną metodę jako abstrakcyjną, która zmusza podklasę do zastąpienia jej.
Błąd kompilacji metody ForEach rozwiązany przy użyciu metody domyślnej
W Javie 8 kolekcje JDK zostały rozszerzone, a metoda forEach została dodana do całej kolekcji (która działa w połączeniu z lambdami). W tradycyjny sposób kod wygląda jak poniżej,
public interface Iterable<T> {
public void forEach(Consumer<? super T> consumer);
}
Ponieważ wynik ten powoduje, że każda klasa implementująca ma błędy kompilacji, dodano domyślną metodę z wymaganą implementacją, aby istniejąca implementacja nie została zmieniona.
Interfejs Iterable z metodą domyślną znajduje się poniżej,
public interface Iterable<T> {
public default void forEach(Consumer
<? super T> consumer) {
for (T t : this) {
consumer.accept(t);
}
}
}
Ten sam mechanizm został użyty do dodania strumienia w interfejsie JDK bez przerywania klas implementujących.
Metoda domyślna i problemy z wieloznacznością dziedziczenia wielokrotnego
Ponieważ klasa Java może implementować wiele interfejsów, a każdy interfejs może zdefiniować domyślną metodę z tą samą sygnaturą metody, dlatego odziedziczone metody mogą ze sobą kolidować.
Rozważ poniższy przykład,
public interface InterfaceA {
default void defaultMethod(){
System.out.println("Interface A default method");
}
}
public interface InterfaceB {
default void defaultMethod(){
System.out.println("Interface B default method");
}
}
public class Impl implements InterfaceA, InterfaceB {
}
Powyższy kod nie zostanie skompilowany z następującym błędem,
java: class Impl dziedziczy niepowiązane wartości domyślne dla defaultMethod () z typów InterfaceA i InterfaceB
Aby naprawić tę klasę, musimy zapewnić domyślną implementację metody:
public class Impl implements InterfaceA, InterfaceB {
public void defaultMethod(){
}
}
Ponadto, jeśli chcemy wywołać domyślną implementację zapewnianą przez którykolwiek z super interfejsów, a nie naszą własną implementację, możemy to zrobić w następujący sposób,
public class Impl implements InterfaceA, InterfaceB {
public void defaultMethod(){
// existing code here..
InterfaceA.super.defaultMethod();
}
}
Możemy wybrać dowolną domyślną implementację lub obie w ramach naszej nowej metody.
Ważne informacje na temat domyślnych metod interfejsu Java:
- Domyślne metody interfejsu Java pomogą nam w rozszerzeniu interfejsów bez obawy przed zerwaniem klas implementacyjnych.
- Domyślne metody interfejsu Java zmniejszyły różnice między interfejsami a klasami abstrakcyjnymi.
- Domyślne metody interfejsu Java 8 pomogą nam uniknąć klas narzędzi, takich jak wszystkie metody klasy Kolekcje mogą być dostarczone w samych interfejsach.
- Domyślne metody interfejsu Java pomogą nam w usunięciu podstawowych klas implementacji, możemy zapewnić implementację domyślną, a klasy implementacji mogą wybrać, którą z nich zastąpić.
- Jednym z głównych powodów wprowadzenia domyślnych metod w interfejsach jest udoskonalenie interfejsu API kolekcji w Javie 8 w celu obsługi wyrażeń lambda.
- Jeśli jakakolwiek klasa w hierarchii ma metodę o tym samym podpisie, wówczas metody domyślne stają się nieistotne. Metoda domyślna nie może zastąpić metody z java.lang.Object. Rozumowanie jest bardzo proste, ponieważ obiekt jest klasą bazową dla wszystkich klas java. Więc nawet jeśli mamy metody klasy Object zdefiniowane jako domyślne w interfejsach, będzie to bezużyteczne, ponieważ metoda klasy Object będzie zawsze używana. Dlatego, aby uniknąć nieporozumień, nie możemy mieć domyślnych metod, które zastępują metody klasy Object.
- Domyślne metody interfejsu Java są również określane jako Metody Defendera lub Metody rozszerzania wirtualnego.
Link do zasobu:
- Interfejs z metodami domyślnymi vs Klasa abstrakcyjna w Javie 8
- Klasa abstrakcyjna a interfejs w erze JDK 8
- Ewolucja interfejsu za pomocą metod rozszerzania wirtualnego
Metoda statyczna interfejsu Java
Metoda statyczna interfejsu Java, przykład kodu, metoda statyczna a metoda domyślna
Metoda statyczna interfejsu Java jest podobna do metody domyślnej, z tym wyjątkiem, że nie możemy ich przesłonić w klasach implementacji. Ta funkcja pomaga nam uniknąć niepożądanych wyników w przypadku złej implementacji w klasach implementacyjnych. Spójrzmy na to na prostym przykładzie.
public interface MyData {
default void print(String str) {
if (!isNull(str))
System.out.println("MyData Print::" + str);
}
static boolean isNull(String str) {
System.out.println("Interface Null Check");
return str == null ? true : "".equals(str) ? true : false;
}
}
Zobaczmy teraz klasę implementacji, która ma metodę isNull () ze słabą implementacją.
public class MyDataImpl implements MyData {
public boolean isNull(String str) {
System.out.println("Impl Null Check");
return str == null ? true : false;
}
public static void main(String args[]){
MyDataImpl obj = new MyDataImpl();
obj.print("");
obj.isNull("abc");
}
}
Zauważ, że isNull (String str) to prosta metoda klasy, nie zastępująca metody interfejsu. Na przykład, jeśli dodamy adnotację @Override do metody isNull (), spowoduje to błąd kompilatora.
Teraz, kiedy uruchomimy aplikację, otrzymamy następujące dane wyjściowe.
Kontrola zerowa interfejsu
Impl Null Check
Jeśli zmienimy metodę interfejsu ze statycznej na domyślną, otrzymamy następujące dane wyjściowe.
Impl Null Check
MyData Print ::
Impl Null Check
Metoda statyczna interfejsu Java jest widoczna tylko dla metod interfejsu, jeśli usuniemy metodę isNull () z klasy MyDataImpl, nie będziemy mogli jej użyć do obiektu MyDataImpl. Jednak podobnie jak inne metody statyczne, możemy używać metod statycznych interfejsu przy użyciu nazwy klasy. Na przykład poprawna instrukcja to:
boolean result = MyData.isNull("abc");
Ważne informacje dotyczące statycznej metody interfejsu Java:
- Metoda statyczna interfejsu Java jest częścią interfejsu, nie możemy jej używać do obiektów klasy implementacji.
- Metody statyczne interfejsu Java są dobre do dostarczania metod narzędziowych, na przykład sprawdzania wartości zerowej, sortowania kolekcji itp.
- Metoda statyczna interfejsu Java pomaga nam zapewnić bezpieczeństwo, nie pozwalając klasom implementacji na ich zastąpienie.
- Nie możemy zdefiniować metody statycznej interfejsu dla metod klasy Object, otrzymamy błąd kompilatora jako „Ta metoda statyczna nie może ukryć metody instancji przed Object”. Jest tak, ponieważ nie jest to dozwolone w Javie, ponieważ Object jest klasą bazową dla wszystkich klas i nie możemy mieć jednej metody statycznej na poziomie klasy i innej metody instancji o tej samej sygnaturze.
- Możemy użyć metod statycznych interfejsu java do usunięcia klas narzędzi, takich jak Kolekcje, i przenieść wszystkie jego metody statyczne do odpowiedniego interfejsu, który byłby łatwy do znalezienia i użycia.
Interfejsy funkcjonalne Java
Zanim zakończę ten post, chciałbym krótko przedstawić interfejsy funkcjonalne. Interfejs z dokładnie jedną metodą abstrakcyjną jest znany jako interfejs funkcjonalny.
Wprowadzono nową adnotację @FunctionalInterface
, aby oznaczyć interfejs jako interfejs funkcjonalny. @FunctionalInterface
adnotacja to funkcja pozwalająca uniknąć przypadkowego dodania metod abstrakcyjnych w interfejsach funkcjonalnych. Korzystanie z niego jest opcjonalne, ale dobrą praktyką.
Interfejsy funkcjonalne są długo wyczekiwaną i bardzo poszukiwaną funkcją Java 8, ponieważ pozwala nam używać wyrażeń lambda do ich tworzenia. Dodano nowy pakiet java.util.function z szeregiem funkcjonalnych interfejsów, aby zapewnić typy docelowe dla wyrażeń lambda i odwołań do metod. W przyszłych postach przyjrzymy się interfejsom funkcjonalnym i wyrażeniom lambda.
Lokalizacja zasobu:
- Zmiany interfejsu Java 8 - metoda statyczna, metoda domyślna