Salut! Parlons des classes abstraites en Java.Exemples concrets de classes abstraites en Java - 1

Pourquoi les cours sont-ils appelés "abstract" ?

Vous vous souvenez probablement de ce qu'est l'abstraction - nous en avons discuté plus tôt :) Si vous avez oublié, pas de soucis. N'oubliez pas qu'il s'agit d'un principe de la POO qui stipule que lors de la conception de classes et de la création d'objets, vous ne devez représenter que les propriétés principales de l'entité et ignorer les propriétés secondaires. Par exemple, si nous concevons une SchoolTeacherclasse, la hauteur ne sera probablement pas une propriété nécessaire d'un enseignant. En effet, cette caractéristique n'est pas importante pour un enseignant. Mais si nous créons une BasketballPlayerclasse, la hauteur sera l'une des caractéristiques les plus importantes. Eh bien, une classe abstraiteest la "pièce brute" la plus abstraite pour un groupe de classes futures. La pièce ne peut pas être utilisée directement — elle est trop "rugueuse". Mais il définit certains états et comportements caractéristiques que les classes futures - les descendants de la classe abstraite - auront.

Exemples de classes abstraites en Java

Prenons un exemple simple avec des voitures :

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;
   }
}
Voici à quoi ressemble la classe abstraite la plus simple. Comme vous pouvez le voir, rien de spécial :) Pourquoi pourrions-nous avoir besoin de cela ? Premièrement, il fournit la description la plus abstraite de l'entité dont nous avons besoin - une voiture. Le mot-clé abstrait signifie quelque chose ici. Dans le monde réel, "juste une voiture" n'existe pas. Il y a des camions, des voitures de course, des berlines, des coupés et des VUS. Notre classe abstraite est simplement un "plan" que nous utiliserons plus tard pour créer des classes de voitures spécifiques.

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!");
   }
  
}
À bien des égards, cela ressemble à ce dont nous avons parlé dans les leçons sur l'héritage. Seulement dans ce cas nous avions une Carclasse dont les méthodes n'étaient pas abstraites. Mais une telle solution présente plusieurs inconvénients qui sont corrigés dans les classes abstraites. Tout d'abord, une instance d'une classe abstraite ne peut pas être créée :

public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // Error! The Car class is abstract!
   }
}
Le créateur de Java a créé cette "fonctionnalité" exprès. Encore une fois, rappelez-vous : une classe abstraite n'est qu'un plan pour les futures classes "régulières" . Vous n'avez pas besoin de copies d'un plan, n'est-ce pas ? De même, il n'est pas nécessaire de créer des instances d'une classe abstraite :) Et si la Carclasse n'était pas abstraite, alors nous pourrions facilement en créer des instances :

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.
   }
}
À l'heure actuelle, notre programme a une sorte de voiture incompréhensible. Ce n'est pas un camion, pas une voiture de course, et pas une berline, mais on ne sait pas vraiment ce que c'est. C'est le "juste une voiture" qui n'existe pas en réalité. Le même exemple peut être donné avec des animaux. Imaginez si votre programme avait Animaldes objets (" juste des animaux "). On ne sait pas de quel type il s'agit, à quelle famille il appartient ou quelles caractéristiques il possède. Il serait étrange d'en voir un dans un programme. Il n'y a pas "que des animaux" dans la nature. Seuls les chiens, les chats, les renards, les taupes, etc. Les classes abstraites nous sauvent des " justes objets ". Ils nous donnent un état et un comportement de base. Par exemple, toutes les voitures doivent avoir un modèle , une couleur et une vitesse maximale, et ils doivent également être capables d' accélérer et de freiner . C'est ça. C'est un plan abstrait général que vous utiliserez plus tard pour concevoir les classes dont vous avez besoin. Remarque : les deux méthodes de la classe abstract sont également abstract , ce qui signifie qu'elles n'ont aucune implémentation. La raison est la même : les classes abstraites ne créent pas de "comportements par défaut" pour "uniquement les voitures". Ils indiquent simplement ce que chaque voiture doit être capable de faire. Cela dit, si vous avez besoin d'un comportement par défaut, vous pouvez implémenter des méthodes dans une classe abstraite. Java ne l'interdit pas :

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();
   }
}
Sortie console :
Accelerating!
Comme vous pouvez le voir, nous avons implémenté une méthode dans la classe abstraite, mais pas l'autre. En conséquence, le comportement de notre Sedanclasse est divisé en deux parties : si nous appelons sa gas()méthode, le comportement est "tiré" de la Carclasse parente abstraite et nous implémentons la brake()méthode dans la Sedanclasse. C'est super pratique et flexible. Mais notre classe n'est plus si abstraite maintenant, n'est-ce pas ? Après tout, il a effectivement mis en œuvre la moitié des méthodes. Le fait est - et c'est une caractéristique très importante - qu'une classe est abstraite si même l'une de ses méthodes est abstraite. Une méthode sur deux, ou une sur mille, peu importe. Nous pourrions même implémenter toutes les méthodes, sans en laisser aucune abstraite. Le résultat serait une classe abstraite sans aucune méthode abstraite. C'est possible en principe — le compilateur ne générera pas d'erreurs — mais il vaut mieux ne pas le faire, car cela prive le mot abstrait de son sens. Vos collègues programmeurs seront également très surpris de voir cela :/ Cela dit, si une méthode est marquée comme abstraite, chaque classe descendante doit l'implémenter ou être déclarée comme abstraite. Sinon, le compilateur renverra une erreur. Bien sûr, chaque classe ne peut hériter que d'une seule classe abstraite, il n'y a donc pas de différence entre les classes abstraites et régulières en termes d'héritage. Peu importe si nous héritons d'une classe abstraite ou régulière — il ne peut y avoir qu'une seule classe parent.

Pourquoi Java n'a pas d'héritage de classes multiples

Nous avons déjà dit qu'il n'y a pas d'héritage multiple en Java, mais nous n'avons pas vraiment approfondi pourquoi. Essayons de le faire maintenant. Le fait est que si Java avait un héritage multiple, les classes enfants ne seraient pas en mesure de décider quel comportement choisir. Disons que nous avons deux classes : Toasteret 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!");
   }
}
Comme vous pouvez le voir, les deux classes ont une on()méthode. Pour le grille-pain, la méthode commence à faire du pain grillé, mais dans le cas de la bombe nucléaire, elle déclenche une explosion. Uh-oh :/ Imaginez maintenant que vous avez décidé (ne me demandez pas pourquoi !) de créer quelque chose entre les deux. Voici votre classe :MysteriousDevice ! Ce code ne fonctionnera pas, bien sûr. Nous le présentons simplement comme un exemple de "ce qui aurait pu être":

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?
   }
}
Voyons ce que nous avons. Le dispositif mystérieux dérive à la fois de Toaster et de NuclearBomb. Les deux ont une on()méthode. En conséquence, il n'est pas clair quelle implémentation doit être exécutée si nous appelons on()un MysteriousDeviceobjet. L'objet ne comprendra pas. Et pour couronner le tout, NuclearBomb n'a pas de off()méthode, donc si nous ne devinons pas correctement, il sera alors impossible d'éteindre l'appareil. Exemples concrets de classes abstraites en Java - 2Ce "malentendu", lorsqu'il n'est pas clair quel comportement doit être exécuté, est précisément la raison pour laquelle les créateurs de Java ont rejeté l'héritage multiple. Cela dit, vous apprendrez que les classes Java peuvent implémenter de nombreuses interfaces.