Fiecare versiune nouă de Java diferă de cele anterioare. Ca exemplu de astfel de schimbare față de materialul pe care l-am acoperit, limbajul nu avea enumsînainte de Java 5.
Metode implicite în interfețe - 1
Tocmai așa, Java 8 este vizibil diferit de Java 7. Nu vom ignora inovațiile importante, desigur. Deoarece vorbim despre interfețe în această lecție, să luăm în considerare o actualizare a limbii: metodele implicite în interfețe . Știți deja că o interfață nu implementează comportamentul . Scopul său este de a descrie ce comportament trebuie să existe în toate obiectele care implementează interfața . Dar dezvoltatorii au întâlnit frecvent situații în care implementarea unei metode a fost aceeași în toate clasele. Să ne uităm la exemplul nostru de mașină veche:

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!");
   }
}
Care crezi că este principala problemă cu acest cod? Probabil ați observat că am scris o grămadă de coduri duplicate! Aceasta este o problemă comună în programare și ar trebui evitată. Este o altă chestiune că nu existau soluții speciale înainte de lansarea Java 8. Când a apărut acea versiune, a devenit posibil să se definească metode implicite și să le implementeze chiar în interiorul unei interfețe! Iată cum să o faci:

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 {

}
Acum metodele gas()și brake(), care erau aceleași pentru toate mașinile, au fost mutate în interfață, eliminând necesitatea codului duplicat. Și metodele sunt disponibile în fiecare dintre clase!

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();
   }
}
Ce se întâmplă dacă există 100 de clase cu o gas()metodă, dar doar 99 dintre ele ar trebui să aibă același comportament? Asta strică totul? O metodă implicită nu va funcționa în acest caz? Bineînțeles că nu :) Metodele implicite de interfață pot fi înlocuite.

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!");
   }
}
Toate celelalte 99 de tipuri de mașini vor folosi metoda implicită, în timp ceUnusualCarclasa este o excepție. Fără a strica imaginea de ansamblu, își va defini calm propriul comportament. Moștenire multiplă în interfețe. După cum știți deja, nu există o moștenire multiplă în Java. Există multe motive pentru aceasta. Le vom analiza în detaliu într-o lecție separată. În alte limbi, cum ar fi C++, situația este inversă. Nicio moștenire multiplă nu prezintă o provocare serioasă, deoarece același obiect poate avea mai multe caracteristici și comportamente diferite. De exemplu, suntem copii pentru părinții noștri, studenți pentru profesorii noștri și pacienți pentru medicii noștri. În viața reală, ocupăm diverse roluri și, în consecință, ne comportăm diferit: evident că interacționăm cu profesorii altfel decât cu prietenii apropiați. Să încercăm să traducem această situație în cod. Să ne imaginăm că avem două clase: Iaz și Volieră. Un iaz are nevoie de păsări care înoată, în timp ce o volieră are nevoie de păsări zburătoare. Pentru a reprezenta acest lucru, am creat două clase de bază:FlyingBirdși Waterfowl.

public class Waterfowl {
}

public class FlyingBird {
}
În consecință, vom trimite păsări care moștenesc FlyingBirdîn volieră, în timp ce cele care derivă din Waterfowlvor merge la iaz. Totul pare simplu. Dar ce ar trebui să facem dacă trebuie să definim o rață undeva? Rațele înoată și zboară. Dar nu avem moștenire multiplă. Din fericire, Java acceptă mai multe implementări de interfețe. Dacă o clasă nu poate moșteni mai mulți părinți, implementarea mai multor interfețe este ușoară! Rața noastră poate fi o pasăre zburătoare, precum și o pasăre care înoată :) Pentru a obține rezultatul dorit, tot ce trebuie să facem este să facem FlyingBirdși să facem Waterfowlinterfețe, mai degrabă decât clase.

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!");
   }
}
Aceasta înseamnă că programul nostru își păstrează capacitatea de a gestiona în mod flexibil cursurile. Când combinăm asta cu metodele implicite, capacitatea noastră de a determina comportamentul obiectelor devine aproape nelimitată! :)