Version sans JavaScript, en lecture seule : les ateliers, les quiz et l’exécution du code n’y sont pas. Version complète · Catalogue · Se connecter

Support de cours · chapitre 2

Synthèse du premier cours : relations, héritage et interfaces

Les trois notions du premier cours, et deux erreurs fréquentes qui les accompagnent, vérifiées en exécutant le code.

Le premier cours comportait trois séquences, chacune consacrée à une notion. Les trois définitions écrites au tableau pendant le cours sont reprises ci-dessous.

Ce que final interdit

Dans l'exemple suivant, l'aile du canard est un champ private final. On pourrait donc penser qu'elle est protégée.

Avant de lancer le programme, essayez de prévoir ce qu'affichera la seconde ligne.

Final.java

class Aile {
    boolean cassee = false;
}

class Canard {

    private final Aile gauche;          // « final » : c'est la RÉFÉRENCE qui est gelée

    Canard(Aile gauche) {
        this.gauche = gauche;
    }

    boolean peutVoler() {
        return !gauche.cassee;
    }
}

class Demo {
    public static void main(String[] args) {
        Aile aile = new Aile();
        Canard gerard = new Canard(aile);

        System.out.println("au départ, Gérard vole : " + gerard.peutVoler());

        aile.cassee = true;             // on casse l'aile sans toucher au champ final

        System.out.println("après l'accident  : " + gerard.peutVoler());
    }
}

Ici, un atelier : on y écrit et on y exécute du code. Il demande JavaScript.

Après avoir lancé : l'explication

Le programme affiche false. L'appelant a conservé une référence vers l'aile et l'a modifiée sans toucher au champ final, qui ne l'en a pas empêché.

Pour voir ce que final interdit, il faut écrire du code dans la classe Canard elle-même, car depuis le main c'est private qui empêcherait l'accès au champ. Ajoutez à Canard la méthode void changerAile(Aile neuve) { gauche = neuve; } : le compilateur la refuse avec le message The final field Canard.gauche cannot be assigned. final interdit seulement de remplacer la référence.

Type déclaré, type réel et méthode appelée

L'exemple comporte deux classes et une seule redéfinition de méthode.

c est déclaré CanardEnPlastique mais contient un CanardSwag. Avant de lancer le programme, essayez de prévoir lequel des deux crie.

Typage.java

class CanardEnPlastique {
    public String crier() { return "coin"; }
}

class CanardSwag extends CanardEnPlastique {
    @Override public String crier() { return "yo"; }
}

class Demo {
    public static void main(String[] args) {
        CanardEnPlastique c = new CanardSwag();

        // Type déclaré : CanardEnPlastique. Type réel : CanardSwag.
        System.out.println("c.crier() donne   : " + c.crier());

        Object o = new CanardSwag();
        System.out.println("o.getClass()      : " + o.getClass().getSimpleName());

        // Décommentez la ligne suivante : le compilateur refuse, alors que
        // l'objet sait parfaitement crier.
        // System.out.println(o.crier());
    }
}

Ici, un atelier : on y écrit et on y exécute du code. Il demande JavaScript.

Après avoir lancé : l'explication

c.crier() affiche yo : la méthode exécutée est celle de l'objet réel. o.getClass() confirme d'ailleurs que l'objet est bien un CanardSwag.

Décommentez ensuite la dernière ligne et relancez. Le compilateur affiche :

The method crier() is undefined for the type Object

L'objet possède bien une méthode crier(), comme getClass() vient de le montrer, mais le compilateur ne tient compte que du type déclaré, et Object n'a pas de méthode crier().