1. Vaardigheden

Om de voordelen van interfaces en waar ze te gebruiken beter te begrijpen, moeten we het hebben over wat meer abstracte zaken.

Een klasse modelleert meestal een bepaald object. Een interface komt minder overeen met objecten, en meer met hun capaciteiten of rollen.

De essentie van interfaces

Zaken als auto's, fietsen, motorfietsen en wielen kunnen bijvoorbeeld het beste worden weergegeven als klassen en objecten. Maar hun capaciteiten - zoals "Ik kan worden bereden", "Ik kan mensen vervoeren", "Ik kan staan" - worden beter gepresenteerd als interfaces. Hier zijn enkele voorbeelden:

Code Beschrijving
interface CanMove
{
   void move(String newLocation);
}
Komt overeen met het vermogen om te bewegen
interface Rideable
{
   void ride(Passenger passenger);
}
Komt overeen met rijvaardigheid
interface CanTransport
{
   void addStuff(Object stuff);
   Object removeStuff();
}
Komt overeen met de mogelijkheid om spullen te vervoeren
class Wheel implements CanMove
{
   ...
}
De Wheelklas kan bewegen
class Car implements CanMove, Rideable, CanTransport
{
   ...
}
De Carklas kan dingen verplaatsen, berijden en vervoeren
class Skateboard implements CanMove, Rideable
{
   ...
}
De Skateboardklas kan bewegen en bereden worden


2. Rollen

Interfaces vereenvoudigen het leven van een programmeur aanzienlijk. Heel vaak heeft een programma duizenden objecten, honderden klassen, maar slechts een paar dozijn interfaces , dwz rollen . Er zijn weinig rollen, maar er zijn veel manieren om ze te combineren (klassen).

Het hele punt is dat je niet voor elke klas code hoeft te schrijven om met elke andere klas te communiceren. U hoeft alleen maar te communiceren met hun rollen (interfaces).

Stel je voor dat je een huisdierentrainer bent. Elk van de huisdieren waarmee je werkt, kan verschillende vaardigheden hebben. U krijgt een vriendschappelijke discussie met uw buurman over wiens huisdieren het meeste lawaai kunnen maken. Om de zaak op te lossen, zet je alle huisdieren die kunnen "spreken" op een rij en geef je ze het commando: Spreek!

Het maakt je niet uit wat voor dier ze zijn of welke andere vaardigheden ze hebben. Zelfs als ze een driedubbele achterwaartse salto kunnen maken. Op dit specifieke moment ben je alleen geïnteresseerd in hun vermogen om luid te spreken. Dit is hoe het eruit zou zien in code:

Code Beschrijving
interface CanSpeak
{
   void speak();
}
Het CanSpeakvermogen. Deze interface begrijpt het commando to speak, wat betekent dat het een overeenkomstige methode heeft.
class Cat implements CanSpeak
{
   void speak()
   {
      println("MEOW");
   }
}

class Dog implements CanSpeak
{
   void speak()
   {
      println("WOOF");
   }
}

class Fish
{
   ...
}
Dieren die deze functie hebben.

Om het begrip te vergemakkelijken, hebben we de klassennamen in het Engels gegeven. Dit is toegestaan ​​in Java, maar het is hoogst onwenselijk.













Onze heeft niet de mogelijkheid om te spreken (implementeert de interface Fishniet ).CanSpeak

public static void main(String[] args)
{
   // Add all the animals to the list
   ArrayList pets = new ArrayList();
   pets.add(new Cat());
   pets.add(new Dog());
   pets.add(new Fish());

   // If the ability exists, then make a sound
   for(Object pet: pets)
   {
      if (pet instanceof CanSpeak)
      {
         CanSpeak loudmouth = (CanSpeak) pet;
         loudmouth.speak();
      }
   }
}
En hoe geven we ze het bevel?

Wanneer het aantal klassen in uw programma's de duizenden bereikt, zult u niet meer zonder interfaces kunnen leven. In plaats van de interactie van duizenden klassen te beschrijven, volstaat het om de interactie van enkele tientallen interfaces te beschrijven - dit vereenvoudigt het leven enorm.

En in combinatie met polymorfisme is deze aanpak over het algemeen een doorslaand succes.



3. De defaultimplementatie van interfacemethoden

Abstracte klassen kunnen variabelen en implementaties van methoden hebben, maar ze kunnen geen meervoudige overerving hebben. Interfaces kunnen geen variabelen of implementaties van methoden hebben, maar dat kan wel meerdere overerving hebben.

De situatie wordt uitgedrukt in de volgende tabel:

Vermogen / eigendom Abstracte lessen Interfaces
Variabelen
Methode implementatie
Meerdere erfenissen

Sommige programmeurs wilden dus echt dat interfaces de mogelijkheid hadden om methode-implementaties te hebben. Maar de mogelijkheid hebben om een ​​methode-implementatie toe te voegen, betekent niet dat er altijd een zal worden toegevoegd. Voeg het toe als je wilt. Of als je dat niet doet, doe het dan niet.

Bovendien zijn problemen met meervoudige overerving voornamelijk te wijten aan variabelen. Dat hebben ze in ieder geval besloten en gedaan. Vanaf JDK 8 introduceerde Java de mogelijkheid om methode-implementaties aan interfaces toe te voegen.

Hier is een bijgewerkte tabel (voor JDK 8 en hoger):

Vermogen / eigendom Abstracte lessen Interfaces
Variabelen
Methode implementatie
Meerdere erfenissen

Nu kunt u zowel voor abstracte klassen als voor interfaces methoden met of zonder implementatie declareren. En dit is uitstekend nieuws!

In abstracte klassen moeten methoden zonder implementatie worden voorafgegaan door het abstracttrefwoord. U hoeft niets toe te voegen vóór methoden met een implementatie. Bij interfaces is het tegenovergestelde waar. Als een methode geen implementatie heeft, hoeft er niets te worden toegevoegd. Maar als er een implementatie is, dan defaultmoet het trefwoord worden toegevoegd.

Voor de eenvoud presenteren we deze informatie in de volgende kleine tabel:

Vermogen / eigendom Abstracte lessen Interfaces
Methoden zonder implementatie abstract
Methoden met een implementatie default

Probleem

Het gebruik van interfaces die methoden hebben, kan grote klassenhiërarchieën aanzienlijk vereenvoudigen. InputStreamDe samenvatting en klassen kunnen bijvoorbeeld OutputStreamworden gedeclareerd als interfaces! Hierdoor kunnen we ze veel vaker en veel handiger gebruiken.

Maar er zijn al tientallen miljoenen (miljarden?) Java-klassen in de wereld. En als je standaardbibliotheken gaat veranderen, maak je misschien iets kapot. Alles leuk vinden! 😛

Om bestaande programma's en bibliotheken niet per ongeluk kapot te maken, werd besloten dat methode-implementaties in interfaces de laagste overervingsprioriteit zouden hebben .

Als een interface bijvoorbeeld een andere interface overerft die een methode heeft, en de eerste interface declareert dezelfde methode maar zonder een implementatie, dan zal de methode-implementatie van de overgeërfde interface de overervende interface niet bereiken. Voorbeeld:

interface Pet
{
   default void meow()
   {
      System.out.println("Meow");
   }
}

interface Cat extends Pet
{
   void meow(); // Here we override the default implementation by omitting an implementation
}

class Tom implements Cat
{
}

De code wordt niet gecompileerd omdat de Tomklasse de methode niet implementeert meow().