288 votes

Classe abstraite en Java

Qu'est-ce qu'une "classe abstraite" en Java ?

349voto

Imagist Points 5348

Une classe abstraite est une classe qui ne peut pas être instanciée. Une classe abstraite est utilisée en créant une sous-classe héritant qui puede être instancié. Une classe abstraite fait quelques choses pour la sous-classe qui en hérite :

  1. Définit les méthodes qui peuvent être utilisées par la sous-classe héritière.
  2. Définit les méthodes abstraites que la sous-classe qui en hérite doit mettre en œuvre.
  3. Fournir une interface commune qui permet à la sous-classe d'être échangée avec toutes les autres sous-classes.

Voici un exemple :

abstract public class AbstractClass
{
    abstract public void abstractMethod();
    public void implementedMethod() { System.out.print("implementedMethod()"); }
    final public void finalMethod() { System.out.print("finalMethod()"); }
}

Remarquez que "abstractMethod()" n'a pas de corps de méthode. Pour cette raison, vous ne pouvez pas faire ce qui suit :

public class ImplementingClass extends AbstractClass
{
    // ERROR!
}

Il n'y a pas de méthode qui implémente abstractMethod() ! Il n'y a donc aucun moyen pour la JVM de savoir ce qu'elle est censée faire lorsqu'elle reçoit quelque chose comme new ImplementingClass().abstractMethod() .

Voici un exemple correct ImplementingClass .

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
}

Remarquez que vous n'avez pas besoin de définir implementedMethod() o finalMethod() . Ils étaient déjà définis par AbstractClass .

Voici un autre correct ImplementingClass .

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
}

Dans ce cas, vous avez remplacé implementedMethod() .

Cependant, en raison de la final mot-clé, ce qui suit n'est pas possible.

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
    public void finalMethod() { System.out.print("ERROR!"); }
}

Vous ne pouvez pas le faire parce que l'implémentation de la fonction finalMethod() en AbstractClass est marqué comme l'implémentation finale de finalMethod() Il n'y a pas d'autres implémentations autorisées, jamais.

Maintenant vous pouvez également implémenter deux fois une classe abstraite :

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
}

// In a separate file.
public class SecondImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("second abstractMethod()"); }
}

Maintenant, quelque part, vous pourriez écrire une autre méthode.

public tryItOut()
{
    ImplementingClass a = new ImplementingClass();
    AbstractClass b = new ImplementingClass();

    a.abstractMethod();    // prints "abstractMethod()"
    a.implementedMethod(); // prints "Overridden!"     <-- same
    a.finalMethod();       // prints "finalMethod()"

    b.abstractMethod();    // prints "abstractMethod()"
    b.implementedMethod(); // prints "Overridden!"     <-- same
    b.finalMethod();       // prints "finalMethod()"

    SecondImplementingClass c = new SecondImplementingClass();
    AbstractClass d = new SecondImplementingClass();

    c.abstractMethod();    // prints "second abstractMethod()"
    c.implementedMethod(); // prints "implementedMethod()"
    c.finalMethod();       // prints "finalMethod()"

    d.abstractMethod();    // prints "second abstractMethod()"
    d.implementedMethod(); // prints "implementedMethod()"
    d.finalMethod();       // prints "finalMethod()"
}

Remarquez que même si nous avons déclaré b un AbstractClass il affiche "Overriden!" . C'est parce que l'objet que nous avons instancié était en fait une ImplementingClass dont implementedMethod() est bien sûr surchargée. (Vous avez peut-être déjà vu ce terme sous le nom de polymorphisme).

Si nous souhaitons accéder à un membre spécifique à une sous-classe particulière, nous devons d'abord effectuer un casting vers cette sous-classe :

// Say ImplementingClass also contains uniqueMethod()
// To access it, we use a cast to tell the runtime which type the object is
AbstractClass b = new ImplementingClass();
((ImplementingClass)b).uniqueMethod();

Enfin, vous ne pouvez pas faire ce qui suit :

public class ImplementingClass extends AbstractClass, SomeOtherAbstractClass
{
    ... // implementation
}

Une seule classe peut être prolongée à la fois. Si vous devez étendre plusieurs classes, elles doivent être des interfaces. Vous pouvez le faire :

public class ImplementingClass extends AbstractClass implements InterfaceA, InterfaceB
{
    ... // implementation
}

Voici un exemple d'interface :

interface InterfaceA
{
    void interfaceMethod();
}

C'est en gros la même chose que :

abstract public class InterfaceA
{
    abstract public void interfaceMethod();
}

La seule différence est que la deuxième méthode ne permet pas au compilateur de savoir qu'il s'agit en fait d'une interface. Cela peut être utile si vous voulez que les gens ne mettent en œuvre que votre interface et aucune autre. Cependant, en règle générale, si votre classe abstraite ne possède que des méthodes abstraites, vous devriez probablement en faire une interface.

Ce qui suit est illégal :

interface InterfaceB
{
    void interfaceMethod() { System.out.print("ERROR!"); }
}

Vous ne pouvez pas implémenter les méthodes d'une interface. Cela signifie que si vous implémentez deux interfaces différentes, les différentes méthodes de ces interfaces ne peuvent pas entrer en conflit. Comme toutes les méthodes d'une interface sont abstraites, vous devez implémenter la méthode, et comme votre méthode est la seule implémentation dans l'arbre d'héritage, le compilateur sait qu'il doit utiliser votre méthode.

77voto

Daniel Rikowski Points 27193

Une classe Java devient abstraite dans les conditions suivantes :

1. Au moins une des méthodes est marquée comme abstraite :

public abstract void myMethod()

Dans ce cas, le compilateur vous oblige à marquer la classe entière comme abstraite.

2. La classe est marquée comme abstraite :

abstract class MyClass

Comme déjà dit : Si vous avez une méthode abstraite, le compilateur vous oblige à marquer la classe entière comme abstraite. Mais même si vous n'avez pas de méthode abstraite, vous pouvez toujours marquer la classe comme abstraite.

Usage courant :

Une utilisation courante des classes abstraites consiste à fournir un aperçu d'une classe, comme le fait une interface. Mais à la différence d'une interface, elle peut déjà fournir des fonctionnalités, c'est-à-dire que certaines parties de la classe sont implémentées et d'autres sont simplement décrites avec une déclaration de méthode. ("abstrait")

Une classe abstraite ne peut pas être instanciée, mais vous pouvez créer une classe concrète basée sur une classe abstraite, qui peut alors être instanciée. Pour ce faire, vous devez hériter de la classe abstraite et remplacer les méthodes abstraites, c'est-à-dire les mettre en œuvre.

25voto

Dev4World Points 1954

Une classe qui est déclarée à l'aide de l'option abstrait Le mot-clé est connu sous le nom de abstract class . L'abstraction est un processus qui consiste à cacher les détails de la mise en œuvre des données et à ne montrer que la fonctionnalité à l'utilisateur. L'abstraction vous permet de vous concentrer sur ce que l'objet fait plutôt que sur la manière dont il le fait.

Principaux éléments de la classe abstraite

  • Une classe abstraite peut ou non contenir des méthodes abstraites. Il peut y avoir des méthodes non abstraites.

    Une méthode abstraite est une méthode qui est déclarée sans un nom de méthode. implémentation (sans accolades, et suivie d'un point-virgule), comme ceci :

    ex : abstract void moveTo(double deltaX, double deltaY);

  • Si une classe a au moins une méthode abstraite, alors cette classe doit être abstraite.

  • Les classes abstraites ne peuvent pas être instanciées (vous n'êtes pas autorisé à créer un objet de classe abstraite).

  • Pour utiliser une classe abstraite, vous devez en hériter d'une autre classe. Fournir des implémentations à toutes les méthodes abstraites de la classe.

  • Si vous héritez d'une classe abstraite, vous devez fournir des implémentations à toutes les méthodes abstraites de cette classe.

Déclarer une classe abstraite Spécifier abstract Le mot-clé avant la classe lors de la déclaration la rend abstraite. Regardez le code ci-dessous :

abstract class AbstractDemo{ }

Déclarer une méthode abstraite Spécifier abstract Le mot-clé avant la méthode lors de la déclaration la rend abstraite. Regardez le code ci-dessous,

abstract void moveTo();//no body

Pourquoi nous devons abstraire les classes

Dans une application de dessin orientée objet, vous pouvez dessiner des cercles, des rectangles, des lignes, des courbes de Bézier et de nombreux autres objets graphiques. Ces objets ont tous certains états (par exemple : position, orientation, couleur de ligne, couleur de remplissage) et comportements (par exemple : déplacer, tourner, redimensionner, dessiner) en commun. Certains de ces états et comportements sont les mêmes pour tous les objets graphiques (par ex : couleur de remplissage, position, et moveTo). D'autres nécessitent une mise en œuvre différente (par exemple, redimensionner ou dessiner). Tous les objets graphiques doivent être capables de se dessiner ou de se redimensionner, ils diffèrent simplement dans la façon dont ils le font.

C'est une situation parfaite pour une superclasse abstraite. Vous pouvez tirer parti des similitudes et déclarer que tous les objets graphiques héritent du même objet parent abstrait (par exemple : GraphicObject ) comme le montre la figure suivante. enter image description here

Tout d'abord, vous déclarez une classe abstraite, GraphicObject Les sous-classes peuvent être utilisées pour fournir des variables membres et des méthodes qui sont entièrement partagées par toutes les sous-classes, telles que la position actuelle et la méthode moveTo. GraphicObject a également déclaré des méthodes abstraites, telles que draw ou resize, qui doivent être implémentées par toutes les sous-classes, mais de manière différente. Le site GraphicObject peut ressembler à quelque chose comme ça :

abstract class GraphicObject {

  void moveTo(int x, int y) {
    // Inside this method we have to change the position of the graphic 
    // object according to x,y     
    // This is the same in every GraphicObject. Then we can implement here. 
  }

  abstract void draw(); // But every GraphicObject drawing case is 
                        // unique, not common. Then we have to create that 
                        // case inside each class. Then create these    
                        // methods as abstract 
  abstract void resize();
}

Utilisation d'une méthode abstraite dans les sous classes Chaque sous-classe non abstraite de GraphicObject comme Circle y Rectangle doivent fournir des implémentations pour l draw y resize méthodes.

class Circle extends GraphicObject {
  void draw() {
    //Add to some implementation here
  }
  void resize() {
    //Add to some implementation here   
  }
}
class Rectangle extends GraphicObject {
  void draw() {
    //Add to some implementation here
  }
  void resize() {
    //Add to some implementation here
  }
}

A l'intérieur de la main vous pouvez appeler toutes les méthodes comme ceci :

public static void main(String args[]){
   GraphicObject c = new Circle();
   c.draw();
   c.resize();
   c.moveTo(4,5);   
}

Façons de réaliser l'abstraction en Java

Il y a deux façons de réaliser l'abstraction en java

  • Classe abstraite (0 à 100%)
  • Interface (100%)

Classe abstraite avec des constructeurs, des membres de données, des méthodes, etc.

abstract class GraphicObject {

  GraphicObject (){
    System.out.println("GraphicObject  is created");
  }
  void moveTo(int y, int x) {
       System.out.println("Change position according to "+ x+ " and " + y);
  }
  abstract void draw();
}

class Circle extends GraphicObject {
  void draw() {
    System.out.println("Draw the Circle");
  }
}

class TestAbstract {  
 public static void main(String args[]){

   GraphicObject  grObj = new Circle ();
   grObj.draw();
   grObj.moveTo(4,6);
 }
}

Sortie :

GraphicObject  is created
Draw the Circle
Change position according to 6 and 4

Rappelez-vous deux règles :

  • Si la classe a peu de méthodes abstraites et peu de méthodes concrètes, déclarez-la comme une abstract classe.

  • Si la classe ne possède que des méthodes abstraites, déclarez-la en tant que classe interface .

Références :

4voto

Noon Silk Points 30396

C'est une classe qui ne peut pas être instanciée, et qui oblige les classes d'implémentation à, éventuellement, implémenter les méthodes abstraites qu'elle décrit.

3voto

Juri Points 14330

En termes simples, vous pouvez considérer une classe abstraite comme une interface avec un peu plus de possibilités.

Vous ne pouvez pas instancier une interface, ce qui vaut également pour une classe abstraite.

Sur votre interface, vous pouvez simplement définir les en-têtes de la méthode et TOUS les implémenteurs sont forcé pour mettre en œuvre tous d'entre eux. Dans une classe abstraite, vous pouvez également définir les en-têtes de votre méthode, mais ici - à la différence de l'interface - vous pouvez également définir le corps (généralement une implémentation par défaut) de la méthode. De plus, lorsque d'autres classes étendent (attention, il ne s'agit pas d'implémenter et donc vous pouvez aussi avoir juste une classe abstraite par classe enfant) de votre classe abstraite, ils ne sont pas obligés d'implémenter toutes les méthodes de votre classe abstraite, sauf si vous avez spécifié un méthode abstraite (dans ce cas, cela fonctionne comme pour les interfaces, vous ne pouvez pas définir le corps de la méthode).

public abstract class MyAbstractClass{
  public abstract void DoSomething();
}

Sinon, pour les méthodes normales d'une classe abstraite, les "héritiers" peuvent soit utiliser le comportement par défaut, soit le surcharger, comme d'habitude.

Exemple :

public abstract class MyAbstractClass{

  public int CalculateCost(int amount){
     //do some default calculations
     //this can be overriden by subclasses if needed
  }

  //this MUST be implemented by subclasses
  public abstract void DoSomething();
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X