Hej! Låt oss prata om abstrakta klasser i Java.Konkreta exempel på abstrakta klasser i Java - 1

Varför kallas klasser "abstrakta"?

Du kommer säkert ihåg vad abstraktion är — vi diskuterade det tidigare :) Om du glömde, oroa dig inte. Kom ihåg att det är en OOP-princip som säger att när du designar klasser och skapar objekt ska du endast representera entitetens huvudegenskaper och kassera sekundära. Till exempel, om vi designar en SchoolTeacherklass kommer höjden förmodligen inte att vara en nödvändig egenskap för en lärare. Denna egenskap är faktiskt inte viktig för en lärare. Men om vi skapar en BasketballPlayerklass kommer höjden att vara en av de viktigaste egenskaperna. Tja, en abstrakt klassär det mest abstrakta, "grova arbetsstycket" för en grupp framtida klasser. Arbetsstycket kan inte användas direkt - det är för "grovt". Men det definierar ett visst karaktäristiskt tillstånd och beteende som framtida klasser - ättlingarna till den abstrakta klassen - kommer att ha.

Exempel på abstrakta klasser i Java

Tänk på ett enkelt exempel med bilar:

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;
   }
}
Så här ser den enklaste abstrakta klassen ut. Som du kan se, inget speciellt :) Varför kan vi behöva detta? För det första ger det den mest abstrakta beskrivningen av den enhet vi behöver - en bil. Det abstrakta nyckelordet betyder något här. I den verkliga världen finns det inget som heter "bara en bil". Det finns lastbilar, racerbilar, sedaner, coupéer och stadsjeepar. Vår abstrakta klass är helt enkelt en "blueprint" som vi senare kommer att använda för att skapa specifika bilklasser.

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!");
   }
  
}
På många sätt liknar detta det vi pratade om på lektionerna om arv. Bara i det fallet hade vi en Carklass vars metoder inte var abstrakta. Men en sådan lösning har flera nackdelar som är fixerade i abstrakta klasser. Först och främst kan en instans av en abstrakt klass inte skapas:

public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // Error! The Car class is abstract!
   }
}
Javas skapare har gjort denna "funktion" med avsikt. Återigen, kom ihåg: en abstrakt klass är bara en plan för framtida "vanliga" klasser . Du behöver inga kopior av en ritning, eller hur? På samma sätt finns det inget behov av att skapa instanser av en abstrakt klass :) Och om klassen Carinte var abstrakt, skulle vi enkelt kunna skapa instanser av den:

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.
   }
}
I dagsläget har vårt program någon form av obegriplig bil. Det är inte en lastbil, inte en racerbil och inte en sedan, men det är inte riktigt klart vad det är. Det är "bara en bil" som inte finns i verkligheten. Samma exempel kan ges med djur. Föreställ dig om ditt program hade Animalobjekt (" bara djur "). Det är inte klart vilken sort det är, vilken familj den tillhör eller vilka egenskaper den har. Det skulle vara konstigt att se en i ett program. Det finns inga "bara djur" i naturen. Endast hundar, katter, rävar, mullvadar etc. Abstrakta klasser räddar oss från " bara föremål ". De ger oss baslinjetillstånd och beteende. Till exempel måste alla bilar ha modell , färg och toppfart, och de måste också kunna ansätta gasen och bromsa . Det är allt. Det är en allmän abstrakt ritning som du kommer att använda senare för att utforma de klasser du behöver. Notera: de två metoderna i abstraktklassen är också abstrakta , vilket betyder att de inte har någon implementering alls. Anledningen är densamma: abstrakta klasser skapar inte "standardbeteenden" för "bara bilar". De anger bara vad varje bil måste klara av. Som sagt, om du behöver standardbeteende kan du implementera metoder i en abstrakt klass. Java förbjuder inte detta:

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();
   }
}
Konsolutgång:
Accelerating!
Som du kan se implementerade vi en metod i abstraktklassen, men inte den andra. Som ett resultat är beteendet för vår Sedanklass uppdelat i två delar: om vi kallar dess gas()metod, "dras" beteendet upp från den abstrakta Carförälderklassen, och vi implementerar brake()metoden i Sedanklassen. Det är superbekvämt och flexibelt. Men vår klass är inte så abstrakt nu, eller hur ? Trots allt implementerade den faktiskt hälften av metoderna. Faktum är – och detta är en mycket viktig egenskap – en klass är abstrakt om ens en av dess metoder är abstrakt. En metod av två, eller en av tusen — det spelar ingen roll. Vi skulle till och med kunna implementera alla metoder utan att lämna någon abstrakt. Resultatet skulle bli en abstrakt klass utan några abstrakta metoder. Detta är möjligt i princip — kompilatorn genererar inga fel — men det är bättre att inte göra detta, eftersom det berövar ordet abstrakt dess betydelse. Dina andra programmerare kommer också att bli mycket förvånade över att se detta :/ Som sagt, om en metod är markerad som abstrakt, måste varje släktklass implementera den eller deklareras som abstrakt. Annars kommer kompilatorn att ge ett fel. Naturligtvis kan varje klass bara ärva en abstrakt klass, så det är ingen skillnad mellan abstrakta och vanliga klasser när det gäller arv. Det spelar ingen roll om vi ärver en abstrakt klass eller en vanlig - det kan bara finnas en förälderklass.

Varför Java inte har flera klasserv

Vi har redan sagt att det inte finns något multipelt arv i Java, men vi har inte riktigt fördjupat oss i varför. Låt oss försöka göra det nu. Faktum är att om Java hade flera arv, skulle barnklasser inte kunna bestämma vilket beteende de ska välja. Låt oss säga att vi har två klasser: Toasteroch 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!");
   }
}
Som du kan se har båda klasserna en on()metod. För brödrosten börjar metoden göra rostat bröd, men i fallet med atombomben utlöser det en explosion. Uh-oh :/ Tänk dig nu att du har bestämt dig (fråga mig inte varför!) för att skapa något däremellan. Här är din klass: MysteriousDevice! Den här koden fungerar naturligtvis inte. Vi presenterar det helt enkelt som ett exempel på "vad som kan ha varit":

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åt oss se vad vi har. Den mystiska enheten kommer från både Brödrost och NuclearBomb samtidigt. Båda har en on()metod. Som ett resultat är det inte klart vilken implementering som ska exekveras om vi anropar on()ett MysteriousDeviceobjekt. Objektet kommer inte att förstå. Och till råga på allt så har NuclearBomb ingen off()metod, så om vi inte gissar rätt så blir det omöjligt att stänga av enheten. Konkreta exempel på abstrakta klasser i Java - 2Detta "missförstånd", när det är oklart vilket beteende som ska utföras, är just anledningen till att Javas skapare avvisade multipelt arv. Som sagt, du kommer att lära dig att Java-klasser kan implementera många gränssnitt.