Hej! Lad os tale om abstrakte klasser i Java.Konkrete eksempler på abstrakte klasser i Java - 1

Hvorfor kaldes klasser "abstrakte"?

Du husker sikkert, hvad abstraktion er - vi diskuterede det tidligere :) Hvis du har glemt det, ingen bekymringer. Husk, det er et OOP-princip , der siger, at når du designer klasser og opretter objekter, skal du kun repræsentere entitetens hovedegenskaber og kassere sekundære. For eksempel, hvis vi designer en SchoolTeacherklasse, vil højde sandsynligvis ikke være en nødvendig egenskab for en lærer. Faktisk er denne egenskab ikke vigtig for en lærer. Men hvis vi opretter en BasketballPlayerklasse, så vil højde være en af ​​de vigtigste egenskaber. Nå, en abstrakt klasseer det mest abstrakte, "grove emne" for en gruppe fremtidige klasser. Emnet kan ikke bruges direkte - det er for "groft". Men det definerer en bestemt karakteristisk tilstand og adfærd, som fremtidige klasser - efterkommerne af den abstrakte klasse - vil have.

Eksempler på abstrakte klasser i Java

Overvej et simpelt eksempel med biler:

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ådan ser den enkleste abstrakte klasse ud. Som du kan se, ikke noget særligt :) Hvorfor kan vi have brug for dette? For det første giver det den mest abstrakte beskrivelse af den enhed, vi har brug for - en bil. Det abstrakte nøgleord betyder noget her. I den virkelige verden er der ikke noget, der hedder "bare en bil". Der er lastbiler, racerbiler, sedaner, coupéer og SUV'er. Vores abstrakte klasse er simpelthen en "blueprint", som vi senere vil bruge til at lave specifikke 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å mange måder ligner dette det, vi talte om i lektionerne om arv. Kun i det tilfælde havde vi en Carklasse, hvis metoder ikke var abstrakte. Men en sådan løsning har flere ulemper, der er løst i abstrakte klasser. Først og fremmest kan en instans af en abstrakt klasse ikke oprettes:

public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // Error! The Car class is abstract!
   }
}
Javas skaber har lavet denne "funktion" med vilje. Endnu en gang, husk: en abstrakt klasse er blot en plan for fremtidige "almindelige" klasser . Du behøver ikke kopier af en plan, vel? På samme måde er der ingen grund til at oprette forekomster af en abstrakt klasse :) Og hvis klassen Carikke var abstrakt, så kunne vi nemt oprette forekomster af 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.
   }
}
På nuværende tidspunkt har vores program en form for uforståelig bil. Det er ikke en lastbil, ikke en racerbil og ikke en sedan, men det er ikke rigtig klart, hvad det er. Det er "bare en bil", der ikke findes i virkeligheden. Det samme eksempel kan gives med dyr. Forestil dig, hvis dit program havde Animalobjekter (" kun dyr "). Det er ikke klart, hvilken slags det er, hvilken familie det tilhører, eller hvilke egenskaber det har. Det ville være mærkeligt at se en i et program. Der er ikke "bare dyr" i naturen. Kun hunde, katte, ræve, muldvarpe osv. Abstrakte klasser redder os fra " bare genstande ". De giver os baseline tilstand og adfærd. For eksempel skal alle biler have model , farve og topfart, og de skal også kunne sætte gassen og bremse . Det er det. Det er en generel abstrakt plan, som du senere vil bruge til at designe de klasser, du har brug for. Bemærk: de to metoder i abstraktklassen er også abstrakte , hvilket betyder, at de slet ikke har nogen implementering. Årsagen er den samme: abstrakte klasser skaber ikke "standardadfærd" for "kun biler". De angiver blot, hvad enhver bil skal kunne. Når det er sagt, hvis du har brug for standardadfærd, kan du implementere metoder i en abstrakt klasse. Java forbyder ikke dette:

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();
   }
}
Konsoludgang:
Accelerating!
Som du kan se, implementerede vi den ene metode i den abstrakte klasse, men ikke den anden. Som et resultat er adfærden i vores Sedanklasse opdelt i to dele: Hvis vi kalder dens gas()metode, bliver adfærden "trukket op" fra den abstrakte Caroverordnede klasse, og vi implementerer brake()metoden i Sedanklassen. Det er super praktisk og fleksibelt. Men vores klasse er ikke så abstrakt nu, vel ? Den implementerede jo faktisk halvdelen af ​​metoderne. Faktum er - og dette er et meget vigtigt træk - en klasse er abstrakt, hvis selv en af ​​dens metoder er abstrakt. En metode af to eller en af ​​tusinde - det er lige meget. Vi kunne endda implementere alle metoderne uden at efterlade nogen abstrakt. Resultatet ville være en abstrakt klasse uden nogen abstrakte metoder. Dette er i princippet muligt - compileren vil ikke generere nogen fejl - men det er bedre ikke at gøre dette, da det fratager ordet abstrakt dets betydning. Dine andre programmører vil også blive meget overrasket over at se dette :/ Når det er sagt, hvis en metode er markeret som abstrakt, skal hver efterkommerklasse implementere den eller blive erklæret som abstrakt. Ellers vil compileren give en fejl. Hver klasse kan selvfølgelig kun arve én abstrakt klasse, så der er ingen forskel på abstrakte og almindelige klasser med hensyn til arv. Det er lige meget, om vi arver en abstrakt klasse eller en almindelig - der kan kun være én overordnet klasse.

Hvorfor Java ikke har flere klasser arv

Vi har allerede sagt, at der ikke er nogen multipel arv i Java, men vi har ikke rigtigt dykket ned i hvorfor. Lad os prøve at gøre det nu. Faktum er, at hvis Java havde flere arv, ville børneklasser ikke være i stand til at bestemme, hvilken adfærd de skulle vælge. Lad os sige, at vi har to klasser: Toasterog 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 begge klasser en on()metode. For brødristeren begynder metoden at lave toast, men i tilfælde af atombomben udløser det en eksplosion. Uh-oh :/ Forestil dig nu, at du har besluttet (spørg mig ikke hvorfor!) for at skabe noget midt imellem. Her er din klasse: MysteriousDevice! Denne kode virker selvfølgelig ikke. Vi præsenterer det blot som et eksempel på "hvad der kunne have været":

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?
   }
}
Lad os se, hvad vi har. Den mystiske enhed stammer fra både Toaster og NuclearBomb på samme tid. Begge har en on()metode. Som et resultat er det ikke klart, hvilken implementering der skal udføres, hvis vi kalder on()på et MysteriousDeviceobjekt. Objektet vil ikke forstå. Og oven i købet har NuclearBomb ikke en off()metode, så hvis vi ikke gætter rigtigt, så vil det være umuligt at slukke for enheden. Konkrete eksempler på abstrakte klasser i Java - 2Denne "misforståelse", når det er uklart, hvilken adfærd der skal udføres, er netop årsagen til, at Javas skabere afviste multiple arv. Når det er sagt, vil du lære, at Java-klasser kan implementere mange grænseflader.