1. Képességek

Ahhoz, hogy jobban megértsük az interfészek előnyeit és használatukat, néhány elvontabb dologról kell beszélnünk.

Egy osztály általában egy adott objektumot modellez. Egy interfész kevésbé felel meg az objektumoknak, sokkal inkább a képességeiknek vagy szerepeiknek.

Az interfészek lényege

Például az autók, kerékpárok, motorkerékpárok és kerekek a legjobban osztályokként és tárgyakként ábrázolhatók. De a képességeiket – mint például a „lovagolhatok”, „tudok embereket szállítani”, „meg tudok állni” – jobban bemutatják interfészként. Íme néhány példa:

Kód Leírás
interface CanMove
{
   void move(String newLocation);
}
Megfelel a mozgásképességnek
interface Rideable
{
   void ride(Passenger passenger);
}
Megfelel a lovaglási képességnek
interface CanTransport
{
   void addStuff(Object stuff);
   Object removeStuff();
}
Megfelel a cuccok szállításának képességének
class Wheel implements CanMove
{
   ...
}
Az Wheelosztály mozoghat
class Car implements CanMove, Rideable, CanTransport
{
   ...
}
Az Carosztály mozoghat , lovagolhat és szállíthat dolgokat
class Skateboard implements CanMove, Rideable
{
   ...
}
Az Skateboardosztály mozoghat és lovagolható


2. Szerepek

Az interfészek nagyban leegyszerűsítik a programozó életét. Nagyon gyakran egy program több ezer objektumot, több száz osztályt, de csak pár tucat interfészt , azaz szerepkört tartalmaz . Kevés a szerepkör, de sokféleképpen kombinálhatóak (osztályok).

A lényeg az, hogy nem kell minden osztályhoz kódot írnod ​​ahhoz, hogy minden más osztállyal kommunikálj. Csak kölcsönhatásba kell lépnie a szerepeikkel (interfészekkel).

Képzeld el, hogy kisállat-oktató vagy. Mindegyik háziállat, akivel dolgozik, többféle képességgel rendelkezhet. Baráti vitába keveredik szomszédjával arról, hogy kinek a házi kedvence tud a legtöbb zajt kiütni. A dolog rendezéséhez csak sorba állítod az összes "beszélni" tudó háziállatot, és kiadod nekik a parancsot: Beszélj!

Nem érdekel, hogy milyen állatról van szó, vagy milyen egyéb képességekkel rendelkeznek. Még akkor is, ha képesek tripla hátszaltót csinálni. Ebben a pillanatban csak az érdekli, hogy képesek-e hangosan beszélni. Így nézne ki kódban:

Kód Leírás
interface CanSpeak
{
   void speak();
}
A CanSpeakképesség. Ez az interfész megérti a parancsot speak, ami azt jelenti, hogy rendelkezik egy megfelelő metódussal.
class Cat implements CanSpeak
{
   void speak()
   {
      println("MEOW");
   }
}

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

class Fish
{
   ...
}
Azok az állatok, amelyek rendelkeznek ezzel a funkcióval.

A könnyebb érthetőség érdekében az osztályok nevét angolul adtuk meg. Ez engedélyezett a Java-ban, de nagyon nem kívánatos.













A mi Fishnem tud beszélni (nem valósítja meg a CanSpeakfelületet).

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();
      }
   }
}
És hogyan adjuk ki nekik a parancsot?

Amikor a programjaiban az órák száma eléri az ezret, nem fog tudni élni felületek nélkül. Több ezer osztály interakciójának leírása helyett elég néhány tucat interfész interakcióját leírni – ez nagyban leegyszerűsíti az életet.

A polimorfizmussal kombinálva ez a megközelítés általában átütő sikert arat.



3. defaultInterfész módszerek megvalósítása

Az absztrakt osztályoknak lehetnek változói és metódusmegvalósításai, de nem lehetnek többszörös öröklődésük. Az interfészek nem tartalmazhatnak változókat vagy metódusmegvalósításokat, de többszörösen öröklődnek.

A helyzetet a következő táblázat mutatja be:

Képesség/tulajdonság Absztrakt osztályok Interfészek
Változók
A módszer megvalósítása
Többszörös öröklés

Tehát néhány programozó valóban azt akarta, hogy az interfészek képesek legyenek metódusmegvalósításra. De a metódusmegvalósítás hozzáadásának képessége nem jelenti azt, hogy egy mindig hozzáadásra kerül. Adja hozzá, ha akarja. Vagy ha nem, akkor ne.

Ezen túlmenően a többszörös örökléssel kapcsolatos problémák elsősorban a változókból adódnak. Mindenesetre így döntöttek és meg is tették. A JDK 8-tól kezdve a Java bevezette a metódusmegvalósítások interfészekhez való hozzáadásának lehetőségét.

Íme egy frissített táblázat (JDK 8 és újabb verziókhoz):

Képesség/tulajdonság Absztrakt osztályok Interfészek
Változók
A módszer megvalósítása
Többszörös öröklés

Mostantól az absztrakt osztályok és interfészek esetében deklarálhat metódusokat implementációval vagy anélkül. És ez kiváló hír!

Az absztrakt osztályokban az implementáció nélküli metódusokat a abstractkulcsszónak kell megelőznie. Nem kell semmit hozzáfűznie a megvalósítással rendelkező metódusok előtt. Az interfészek esetében ennek az ellenkezője igaz. Ha egy metódusnak nincs implementációja, akkor semmit sem kell hozzáadni. De ha van implementáció, akkor defaulthozzá kell adni a kulcsszót.

Az egyszerűség kedvéért ezeket az információkat a következő kis táblázatban mutatjuk be:

Képesség/tulajdonság Absztrakt osztályok Interfészek
Megvalósítás nélküli módszerek abstract
Módszerek megvalósítással default

Probléma

A metódusokkal rendelkező interfészek használata nagymértékben leegyszerűsítheti a nagy osztályhierarchiákat. Például az absztrakt InputStreamés OutputStreamaz osztályok deklarálhatók interfészként! Így sokkal gyakrabban és kényelmesebben használhatjuk őket.

De már több tízmillió (milliárd?) Java osztály létezik a világon. És ha elkezdi megváltoztatni a szabványos könyvtárakat, akkor eltörhet valamit. Mint minden! 😛

Annak érdekében, hogy véletlenül se törjenek szét a meglévő programok és könyvtárak, úgy döntöttek, hogy az interfészek metódus-megvalósításainak lesz a legalacsonyabb öröklődési prioritása .

Például, ha az egyik interfész egy másik interfészt örököl, amelynek van metódusa, és az első interfész ugyanazt a metódust deklarálja, de implementáció nélkül, akkor az örökölt interfész metódus-megvalósítása nem éri el az öröklődő interfészt. Példa:

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
{
}

A kód nem fordul le, mert az Tomosztály nem valósítja meg a meow()metódust.