Szia! Beszéljünk a Java absztrakt osztályairól .Konkrét példák absztrakt osztályokra a Java nyelven - 1

Miért nevezik az osztályokat "absztraktnak"?

Valószínűleg emlékszel, mi az absztrakció – korábban már beszéltünk róla :) Ha elfelejtette, ne aggódjon. Ne feledje, ez egy OOP-elv , amely szerint osztályok tervezésekor és objektumok létrehozásakor csak az entitás fő tulajdonságait kell megjeleníteni, a másodlagosakat pedig el kell vetni. Például, ha osztályt tervezünk SchoolTeacher, a magasság valószínűleg nem lesz a tanár szükséges tulajdonsága. Valójában ez a tulajdonság nem fontos egy tanár számára. De ha osztályt hozunk létre BasketballPlayer, akkor a magasság lesz az egyik legfontosabb jellemző. Nos, egy absztrakt osztálya legelvontabb, "durva munkadarab" a jövőbeli osztályok csoportja számára. A munkadarab nem használható közvetlenül - túl "durva". De meghatároz egy bizonyos jellemző állapotot és viselkedést, amellyel a jövő osztályai – az absztrakt osztály leszármazottai – rendelkezni fognak.

Példák absztrakt osztályokra a Java nyelven

Vegyünk egy egyszerű példát autókkal:

public abstract class Car {

   private String model;
   private String color;
   private int maxSpeed;
  
   public abstract void gas();

   public abstract void brake();

   public String getModel() {
       return model;
   }

   public void setModel(String model) {
       this.model = model;
   }

   public String getColor() {
       return color;
   }

   public void setColor(String color) {
       this.color = color;
   }

   public int getMaxSpeed() {
       return maxSpeed;
   }

   public void setMaxSpeed(int maxSpeed) {
       this.maxSpeed = maxSpeed;
   }
}
Így néz ki a legegyszerűbb absztrakt osztály. Amint látod, semmi különös :) Miért lehet erre szükségünk? Először is a legelvontabb leírást adja a szükséges entitásról – egy autóról. Az absztrakt kulcsszó itt jelent valamit. A való világban nincs olyan, hogy „csak egy autó”. Vannak teherautók, versenyautók, szedánok, kupék és terepjárók. Absztrakt osztályunk egyszerűen egy „tervrajz”, amelyet később konkrét autóosztályok létrehozására fogunk használni.

public class Sedan extends Car {
  
   @Override
   public void gas() {
       System.out.println("The sedan is accelerating!");
   }

   @Override
   public void brake() {
       System.out.println("The sedan is slowing down!");
   }
  
}
Ez sok tekintetben hasonlít ahhoz, amiről az örökléssel foglalkozó leckéken beszéltünk. Csak ebben az esetben volt egy Carosztályunk, amelynek a metódusai nem voltak elvontak. De egy ilyen megoldásnak számos hátránya van, amelyeket az absztrakt osztályokban rögzítenek. Először is, egy absztrakt osztály példánya nem hozható létre:

public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // Error! The Car class is abstract!
   }
}
A Java készítője szándékosan hozta létre ezt a "funkciót". Még egyszer ne feledje: az absztrakt osztály csak egy tervrajz a jövőbeni "rendes" osztályokhoz . Nincs szükséged a tervrajz másolataira, igaz? Hasonlóképpen, nem kell egy absztrakt osztály példányait létrehozni :) És ha az Carosztály nem lenne absztrakt, akkor könnyen létrehozhatunk belőle példányokat:

public class Car {

   private String model;
   private String color;
   private int maxSpeed;
  
   public void go() {
       // ...some logic
   }

   public  void brake() {
       // ...some logic
   }
}


public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // This is okay. The car is created.
   }
}
Jelenleg a programunkban van valamiféle érthetetlen autó. Nem teherautó, nem versenyautó és nem szedán, de nem igazán világos, hogy mi az. Ez a „csak egy autó”, ami a valóságban nem létezik. Ugyanezt a példát az állatokkal is felhozhatjuk. Képzeld el, ha a programodban vannak Animalobjektumok (" csak állatok "). Nem világos, hogy milyen fajta, milyen családhoz tartozik, vagy milyen jellemzői vannak. Furcsa lenne ilyet látni egy programban. A természetben nincsenek "csak állatok". Csak a kutyák, macskák, rókák, vakondok stb. Az absztrakt osztályok megmentenek minket a " csak tárgyaktól ". Alapállapotot és viselkedést adnak nekünk. Például minden autónak rendelkeznie kell egy modellel , színnel és maximális sebességgel, és tudniuk kell működtetni a gázt és a féket . Ez az. Ez egy általános absztrakt terv, amelyet később felhasználhat a szükséges osztályok megtervezéséhez. Megjegyzés: az absztrakt osztály két metódusa is abstract , ami azt jelenti, hogy egyáltalán nincs implementációjuk. Az ok ugyanaz: az absztrakt osztályok nem hoznak létre „alapértelmezett viselkedést” a „csak autók” számára. Csak azt jelzik, hogy minden autónak mire kell képesnek lennie. Ennek ellenére, ha alapértelmezett viselkedésre van szüksége, akkor a metódusokat megvalósíthatja egy absztrakt osztályban. A Java ezt nem tiltja:

public abstract class Car {

   private String model;
   private String color;
   private int maxSpeed;

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

   public abstract void brake();
  
   // Getters and setters
}


public class Sedan extends Car {

   @Override
   public void brake() {
       System.out.println("The sedan is slowing down!");
   }

}

public class Main {

   public static void main(String[] args) {

       Sedan sedan = new Sedan();
       sedan.gas();
   }
}
Konzol kimenet:
Accelerating!
Mint látható, az egyik metódust implementáltuk az absztrakt osztályban, a másikat nem. Ennek eredményeként osztályunk viselkedése Sedankét részre oszlik: ha a metódusát hívjuk gas(), akkor a viselkedés "felhúzódik" az absztrakt Carszülőosztályból, és implementáljuk a brake()metódust az Sedanosztályban. Ez szuper kényelmes és rugalmas. De a mi osztályunk most nem olyan elvont, igaz ? Végül is a módszerek felét megvalósította. Az a tény – és ez egy nagyon fontos jellemző – egy osztály absztrakt, ha akár az egyik metódusa is absztrakt. Egy módszer kettőből, vagy egy az ezerből – nem számít. Akár az összes módszert megvalósíthatnánk úgy, hogy egyik sem marad absztrakt. Az eredmény egy absztrakt osztály lenne absztrakt módszerek nélkül. Ez elvileg lehetséges – a fordító nem generál semmilyen hibát –, de jobb, ha ezt nem tesszük, mert megfosztja az absztrakt szót jelentésétől. A programozótársaid is nagyon meg fognak lepődni, ha ezt látják :/ Ez azt jelenti, hogy ha egy metódus absztraktként van megjelölve, akkor minden leszármazott osztálynak implementálnia kell azt, vagy absztraktnak kell deklarálnia. Ellenkező esetben a fordító hibát jelez. Természetesen minden osztály csak egy absztrakt osztályt örökölhet, így öröklődés szempontjából nincs különbség az absztrakt és a reguláris osztályok között. Nem számít, hogy absztrakt vagy reguláris osztályt örökölünk - csak egy szülőosztály lehet.

Miért nincs a Java több osztály öröklődése?

Azt már mondtuk, hogy a Java-ban nincs többszörös öröklődés, de nem igazán elmélyültünk, hogy miért. Próbáljuk meg most megtenni. A helyzet az, hogy ha a Java többszörös öröklődésű, akkor a gyermekosztályok nem tudnák eldönteni, hogy melyik viselkedést válasszák. Tegyük fel, hogy két osztályunk van: Toasterés NuclearBomb:

public class Toaster {
  
  
 public void on() {

       System.out.println("The toaster is on. We're toasting!");
   }
  
   public void off() {

       System.out.println("The toaster is off!");
   }
}


public class NuclearBomb {

   public void on() {

       System.out.println("Boom!");
   }
}
Mint látható, mindkét osztálynak van egy on()metódusa. A kenyérpirítónál a módszer elkezd pirítóst készíteni, de az atombomba esetében robbanást indít el. Uh-ó :/ Most képzeld el, hogy úgy döntöttél (ne kérdezd miért!), hogy létrehozol valamit a kettő között. Íme az osztályod: MysteriousDevice! Ez a kód természetesen nem fog működni. Egyszerűen csak példaként mutatjuk be, hogy "mi lehetett volna":

public class MysteriousDevice extends Toster, NuclearBomb {

   public static void main(String[] args) {
      
       MysteriousDevice mysteriousDevice = new MysteriousDevice();
       mysteriousDevice.on(); // And what should happen here? Will we get toast or a nuclear apocalypse?
   }
}
Lássuk, mi van. A titokzatos eszköz egyidejűleg a Toasterből és a NuclearBombból származik. Mindkettőnek van on()módszere. Ennek eredményeként nem világos, hogy melyik megvalósítást kell végrehajtani, ha meghívunk on()egy MysteriousDeviceobjektumot. A tárgy nem fogja megérteni. És a tetejébe a NuclearBombnak nincs off()módszere, így ha nem jól tippelünk, akkor lehetetlen lesz kikapcsolni a készüléket. Konkrét példák absztrakt osztályokra a Java nyelven - 2Ez a "félreértés", amikor nem világos, hogy melyik viselkedést kell végrehajtani, pontosan az oka annak, hogy a Java alkotói elutasították a többszörös öröklődést. Ennek ellenére megtudhatja, hogy a Java osztályok számos interfészt képesek megvalósítani.