page précédantetable des matièrespage suivante

Dérivation et héritage

Les classes Java sont ordonnées dans un arbre d'héritage. Une classes peut être déclarée comme une sous-classe (ou classe dérivée) en utilisant le mot clé extends. Une sous-classe hérite des variables et des méthodes de sa classe mère (super-classe, classe de base) et les utilise comme si elle les avait déclarées elle-même.En Java tous les classes sont dérivées d'une super-classe - "objet". Donc chaque classe créée hérite ses membres.

class SupClasse{
        float fl;
        …
        void func() {…}
        …
}

class SousClasse extends supClasse{ //fl et func() hérités
        int in;
        …
        void func2(){…};
        …
}

Dans cette exemple un objet de type "SousClasse" possède à la fois la variable fl et la méthode func().

Java autorise l'héritage simple. Ca veut dire q'une classe peut avoir une seule classe de base.

La sous-classe peut être à nouveau dérivée. Normalement la dérivation est utilisée pour la spécialisation d'une classe en y ajoutant des variables et des méthodes.

Redéfinitions des variables

Dans une sous classe on peut déclaré une variable qui porte le nom d'une variable déjà déclarée dans la super-classe. Dans ce cas elle masque la variable de même nom dans la classe de base. Les deux variables continuent à hexister: les méthodes de la classe de base voient la variable originale et les méthodes de la classe dérivée – la nouvelle variable. Le choix des variables qui sont vues par les différentes méthodes est effectué d'une manière statique lors de compilation.

class SupClasse{
        int s;
        …
}

class SousClasse extends supClasse{
        int s;
        …
}

Si dans la sous-classe on doit référencer la variable de la classe de base on utilise le mot – clé super:

        int s1 = super.s;

Redéfinition des méthodes

On a vu déjà qu'il est possible pour la même classe de déclarer des méthodes surchargées. Mais dans une sous – classe on peut redéfinir une méthode qui possède exactement la même signature (nom, arguments et type de retour) que dans sa classe de base. Dans ce cas, la méthode de la classe dérivée remplace la méthode de la classe de base. Redéfinir les méthodes pour changer le comportement d'objets est une autre forme du polymorphisme.

 
exemple lancement avec java Shapes


class Shape {
    public String toString() { return "Shape"; }
}

class Circle extends Shape {
    public String toString() { return "Circle"; }
}

class Square extends Shape {
    public String toString() { return "Square"; }
}

class Triangle extends Shape {
    public String toString() { return "Triangle"; }
}

public class Shapes{
    public static void main(String a[]){
        Shape[] sh = {new Shape(),new Circle(), new Square(), new Triangle()};
        for (int i=0; i< sh.length; i++)
            System.out.println(i+": "+sh[i]);
    }
}

       0: Shape        
       1: Circle
       2: Square
       3: Triangle

Les méthodes surchargées sont choisies lors de compilation( early binding; statik link). Par contre les méthodes redéfinies sont choisies dynamiquement lors de l'exécution (late binding).

Si il y une différence dans la signature de méthode redéfinit le résultat sera une surcharge de méthode.

//: Savon.java
// Héritage et surdefinition

class Detergent {
        private String s = new String("Detergent");
        public void ajouter(String a) { s += a; }
        public void dissoudre() { ajouter(" dissoudre()"); }
        public void appliquer() { ajouter(" appliquer()"); }
        public void frotter() { ajouter(" frotter()"); }
        public void imprimer() { System.out.println(s); }
        public static void main(String[] args) {
                Detergent x = new Detergent();
                x.dissoudre(); x.appliquer(); x.frotter(); x.imprimer();
        }
}

public class Savon extends Detergent {   // Change a method:
        public void frotter() {
                ajouter(" Savon.frotter()");
                super.frotter(); // Appel la méthode de la classe de base
        }
        public void ecumer() { ajouter(" ecumer()"); }   // Ajoute une méthode:
        public static void main(String[] args) {   // Teste la classe dérivée:
                Savon x = new Savon();
                x.dissoudre();  x.appliquer();  x.frotter();  x.ecumer();  x.imprimer();
                System.out.println("Testing base class:");
                Detergent.main(args);
        }
}

résultat de java Savon:

        Detergent dissoudre() appliquer() Savon.frotter() frotter() ecumer()
        Testing base class:
        Detergent dissoudre() appliquer() frotter()

résultat de java Detergent

        Detergent dissoudre() appliquer() frotter()

Appel des constructeurs

//: Savon.java
// Héritage et surdefinition – constructeurs sans paramètres

class Detergent {
        private String s = new String("Detergent");
        Detergent() {System.out.println("constructeur Detergent "); }
        public void ajouter(String a) { s += a; }
        public void dissoudre() { ajouter(" dissoudre()"); }
        public void appliquer() { ajouter(" appliquer()"); }
        public void frotter() { ajouter(" frotter()"); }
        public void imprimer() { System.out.println(s); }
}

public class Savon extends Detergent {
        Savon() {System.out.println("constructeur Savon"); }
        public void frotter() {
                ajouter(" Savon.frotter()");
                super.frotter(); // Appel la méthode de la classe de base
        }
        public void ecumer() { ajouter(" ecumer()"); }
        public static void main(String[] args) {
                Savon x = new Savon();
                x.dissoudre(); x.appliquer(); x.frotter(); x.ecumer(); x.imprimer();
        }
}

résultat de java Savon

        constructeur Detergent
        constructeur Savon
        Detergent dissoudre() appliquer() Savon.frotter() frotter() ecumer()

Constructeurs avec des paramètres

//: Savon.java
// Héritage et surdefinition – constructeurs avec paramètres

class Detergent {
        private String s = new String("Detergent");
        Detergent(int i) {System.out.println("constructeur Detergent " +i); }
        public void ajouter(String a) { s += a; }
        public void dissoudre() { ajouter(" dissoudre()"); }
        public void appliquer() { ajouter(" appliquer()"); }
        public void frotter() { ajouter(" frotter()"); }
        public void imprimer() { System.out.println(s); }
}

public class Savon extends Detergent {
        Savon(int i) {
                super(i-4);
                System.out.println("constructeur Savon");
        }
        public void frotter() {
                ajouter(" Savon.frotter()");
                super.frotter(); // Appel la méthode de la classe de base
        }
        public void ecumer() { ajouter(" ecumer()"); }
        public static void main(String[] args) {
                Savon x = new Savon(10);
                x.dissoudre(); x.appliquer(); x.frotter(); x.ecumer(); x.imprimer();
        }
}

Un exemple

public class Bc {
    int s=4;
    void prt(){System.out.println("prt in Bc - s ="+s);}
}

public class Ec extends Bc{
    int s=12;
    void prt(){System.out.println("prt in Ec - s="+s+" super.s=" +super.s);}
}

public class Test {
    public static void main(String a[]){
        Ec e= new Ec();
        Bc b=e;
        Bc b2= new Bc();
        e.prt();
        b.prt();
        b2.prt();
        System.out.println("e.s="+e.s);
        System.out.println("((Bc)e).s="+((Bc)e).s);
        System.out.println("b.s="+b.s);
        System.out.println("((Ec)b).s="+((Ec)b).s);
        System.out.println("((Ec)b2).s="+((Ec)b2).s);
    }
}
prt in Ec - s=12 super.s=4
prt in Ec - s=12 super.s=4
prt in Bc - s =4
e.s=12
((Bc)e).s=4
b.s=4
((Ec)b).s=12
Exception in thread "main" java.lang.ClassCastException: Bc cannot be cast to Ec
    at Test.main(Test.java:14)

Méthodes et classes abstraite

Comme en C++, une méthode peut être déclarée avec le modificateur abstract pour spécifier qu'il s'agit uniquement d'un prototype. Une méthode abstraite n'a pas d'instruction: ce n'ai qu'une signature suivie par une point virgule:

        abstract type nomDeMéthode (type nomParamètre, …);

En Java, une classe qui contient une ou plusieurs méthodes abstraites doit être explicitement déclarée comme étant une classe abstraite:

abstract class NomClass{
        …
        abstract int methodeAbstrait (int par1);
        …
}

Il peut contenir d'autre méthodes qui ne sont pas abstraites ainsi que des déclarations de variables.

On ne peut pas créer des objets d'une classe abstraite. Pour être utilisé, elle doit être dérivée et ses méthodes abstraites doit être redéfinies par des méthodes qui ne sont pas abstraites. Il n'est pas nécessaire que toute les méthodes abstraites soient redéfinies dans une seule classe dérivée, mais une classe dérivée, qui ne redéfinie pas toutes les méthodes abstraites de la classe de base doit être également définie abstraites.

Les méthodes abstraites fournissent un modèle puissant pour créer des classes dérivée pour des applications spécifiques. Par exemple, la classe java.io.InputStream possède une seule méthode abstraite appelée read(). Ses differentes classes dérivées implémentent cette méthode à leur manière pour leur propre sources de données. La reste de la classe fournit des fonctionnalités étendues base sur la méthode read().

Exemple:

abstract public class Instrument {
    abstract void play();
    Instrument(){
        System.out.println("Construire un instrument");
    }
}
Construire un instrument
construire un tambour
jouer d'un tambour

Construire un instrument
construire un violon
jouer d'un violon

Construire un instrument
construire un tambour
jouer d'un tambour

Construire un instrument
construire un violon
jouer d'un violon

Construire un instrument
construire un violon
jouer d'un violon
public class Violon extends Instrument{
    void play(){
        System.out.println ("jouer d'un violon\n");
    }
    Violon(){
        System.out.println("construire un violon");
    }
}
public class Tambour extends Instrument{
    void play(){
        System.out.println ("jouer d'un tambour\n");
    }
    Tambour(){
        System.out.println("construire un tambour");
    }
}
public class Progr {
    public static void main(String [] args){
        Instrument orchestra[]= new Instrument[5];
        for(int i=0; i<orchestra.length;i++){
            boolean flag= Math.random()>0.5;
            if(flag) orchestra[i]=new Violon();
            else orchestra[i]=new Tambour();
            orchestra[i].play();
        }
    }
}


Exemple:

class Shape {

Color color; // Color of the shape. (

void setColor(Color newColor) {
// Method to change the color of the shape.
color = newColor; // change value of instance variable
redraw(); // redraw shape, which will appear in new color
}

abstract void redraw(); {

} // end of class Shape
class Rectangle extends Shape {
void redraw() {
. . . // commands for drawing a rectangle
}
. . . // possibly, more methods and variables
}
class Oval extends Shape {
void redraw() {
. . . // commands for drawing an oval
}
. . . // possibly, more methods and variables
}
class RoundRect extends Shape {
void redraw() {
. . . // commands for drawing a rounded rectangle
}
. . . // possibly, more methods and variables
}

page précédantetable des matièrespage suivante