Każda nowa wersja Javy różni się od poprzednich. Oto przykład zmian w stosunku do materiału, przez który przechodziliśmy: Przed Javą 5 enumsw języku nie było „.
Domyślne metody w interfejsach - 1
Tak więc Java 8 różni się zauważalnie od Javy 7. Oczywiście nie będziemy ignorować ważnych innowacji. Ponieważ w tym wykładzie mówimy o interfejsach, rozważymy jedną aktualizację - domyślne metody w interfejsach . Wiesz już, że interfejs nie implementuje zachowania . Jego zadaniem jest opisanie, jakie zachowanie powinny mieć wszystkie obiekty, które go implementują . Ale dość często programiści spotykali się z sytuacjami, w których implementacja metody we wszystkich klasach była taka sama. Spójrzmy na przykład naszego starego samochodu:

public interface Car {

   public void gas();
  
   public void brake();
}
public class Sedan implements Car {

   @Override
   public void gas() {
       System.out.println("Gas!");
   }

   @Override
   public void brake() {
       System.out.println("Brake!");
   }
}


public class Truck implements Car {

   @Override
   public void go() {
       System.out.println("Gas!");
   }

   @Override
   public void brake() {
       System.out.println("Brake!");
   }
}


public class F1Car implements Car {
   @Override
   public void go() {
       System.out.println("Gas!");
   }

   @Override
   public void brake() {
       System.out.println("Brake!");
   }
}
Jak myślisz, jaki jest główny problem z tym kodem? Pewnie zauważyłeś, że napisaliśmy sporo tego samego kodu! Ten problem jest powszechny w programowaniu i należy go unikać. Inna sprawa, że ​​przed wydaniem Javy 8 nie było specjalnych rozwiązań. Kiedy pojawiła się ta wersja, stało się możliwe definiowanie domyślnych metod i implementowanie ich bezpośrednio w interfejsie! Oto jak to się robi:

public interface Car {

   public default void gas() {
       System.out.println("Gas!");
   }

   public default void brake() {
       System.out.println("Brake!");
   }
}

public class Sedan implements Car {

}

public class Truck implements Car {

}

public class F1Car implements Car {

}
Teraz metody gas()i brake(), które były takie same dla wszystkich maszyn, zostały przeniesione do interfejsu, a powtarzany kod nie jest potrzebny. Co więcej, w każdym z zajęć dostępne są metody!

public class Main {

   public static void main(String[] args) {

       F1Car f1Car = new F1Car();
       Sedan sedan = new Sedan();
       Truck truck = new Truck();
       truck.gas();
       sedan.gas();
       f1Car.brake();
   }
}
Co jeśli istnieje 100 klas z metodą, gas()ale tylko 99 z nich zachowuje się tak samo? Wszystko psuje, a domyślna metoda nie zadziała w tym przypadku? Oczywiście, że nie :) Domyślne metody interfejsów można nadpisać.

public class UnusualCar implements Car {
   @Override
   public void go() {
       System.out.println("This car accelerates differently!");
   }

   @Override
   public void brake() {
       System.out.println("This car slows down differently!");
   }
}
Wszystkie pozostałe 99 typów maszyn zaimplementuje metodę domyślną i klasęUnusualCar- wyjątek - nie psuje całości obrazu i spokojnie determinuje jego zachowanie. Wielokrotne dziedziczenie w interfejsach Jak już wiesz, w Javie nie ma wielokrotnego dziedziczenia. Jest tego wiele powodów, rozważymy je szczegółowo w osobnym wykładzie. W innych językach, na przykład w C++, jest odwrotnie. Bez wielokrotnego dziedziczenia pojawia się poważny problem: ten sam obiekt może mieć wiele różnych cech i „zachowań”. Przykład z życia: dla rodziców jesteśmy dziećmi, dla nauczycieli uczniami, dla lekarzy pacjentami. W życiu pojawiamy się w różnych rolach iw związku z tym inaczej się zachowujemy: z nauczycielami oczywiście będziemy rozmawiać inaczej niż z bliskimi przyjaciółmi. Spróbujmy przełożyć tę sytuację na kod. Wyobraźmy sobie, że mamy dwie klasy: Pond i Aviary. Staw potrzebuje pływających ptaków, a dla lotnictwa - latanie. W tym celu stworzyliśmy dwie klasy bazowe −FlyingBirdi Waterfowl.

public class Waterfowl {
}

public class FlyingBird {
}
W związku z tym wyślemy do FlyingBirdstawu te ptaki, których klasy są odziedziczone po , i te, które pochodzą z Waterfowl. Wszystko wydaje się proste. Ale co zrobimy, jeśli będziemy musieli gdzieś zdefiniować kaczkę? Ona pływa i lata. Nie mamy wielokrotnego dziedziczenia. Na szczęście Java zapewnia wiele implementacji interfejsów. Jeśli klasa nie może dziedziczyć po wielu rodzicach, implementacja wielu interfejsów jest łatwa! Nasza kaczka potrafi zarówno latać, jak i pływać :) Wystarczy zrobić FlyingBirdnie Waterfowlz klasami, ale z interfejsami, aby osiągnąć zamierzony efekt.

public class Duck implements FlyingBird, Waterfowl {

   // Methods of both interfaces combine easily into one class
  
   @Override
   public void fly() {
       System.out.println("Flying!");
   }

   @Override
   public void swim() {

       System.out.println("Swimming!");
   }
}
Dzięki temu nasz program zachowuje elastyczne zarządzanie klasami, a w połączeniu z implementacją metod domyślnych nasze możliwości określania zachowania obiektów stają się niemal nieograniczone! :)