Énumérations et annotations en Java : concepts fondamentaux

  1. Énumérations

1.1 Pourquoi utiliser une énumération ?

Prenons l'exemple des marques de voitures : il existe un nombre limité de valeurs (BMW, Audi, Mercedes, etc.). Si l'on utilise une classe classique, on peut créer des objets arbitraires, ce qui ne correspond pas à la réalité métier. L'énumération permet de définir un ensemble fixe de constantes.

// Exemple problématique avec une classe classique
class MarqueVoiture {
    private String nom;
    private String pays;

    public MarqueVoiture(String nom, String pays) {
        this.nom = nom;
        this.pays = pays;
    }
    // getters et setters...

    public static void main(String[] args) {
        MarqueVoiture bmw = new MarqueVoiture("BMW", "Allemagne");
        MarqueVoiture audi = new MarqueVoiture("Audi", "Allemagne");
        // Problème : on peut ajouter n'importe quoi
        MarqueVoiture fictif = new MarqueVoiture("Fictif", "Inconnu");
    }
}

1.2 Implémentation manuelle d'une énumération

Avant l'introduction du mot-clé enum, on pouvait simuler une énumération en rendant le constructeur privé et en définissant des constantes public static final.

class MarqueVoiture {
    private String nom;
    private String pays;

    public static final MarqueVoiture BMW = new MarqueVoiture("BMW", "Allemagne");
    public static final MarqueVoiture AUDI = new MarqueVoiture("Audi", "Allemagne");
    public static final MarqueVoiture MERCEDES = new MarqueVoiture("Mercedes", "Allemagne");

    private MarqueVoiture(String nom, String pays) {
        this.nom = nom;
        this.pays = pays;
    }

    public String getNom() {
        return nom;
    }
    public String getPays() {
        return pays;
    }

    @Override
    public String toString() {
        return "MarqueVoiture{" +
                "nom='" + nom + '\'' +
                ", pays='" + pays + '\'' +
                '}';
    }
}

Points clés :

  • Constructeur privé : empêche la création d'instances externes.
  • Attributs final static : garantit l'uniicté et l'immuabilité.
  • Pas de setters : les objets sont en lecture seule.

1.3 Utilisation du mot-clé enum

Java 5 a introduit le mot-clé enum qui simplifie grandement la définition.

enum MarqueVoiture {
    BMW("Allemagne"),
    AUDI("Allemagne"),
    MERCEDES("Allemagne"),
    TOYOTA("Japon");

    private String pays;

    private MarqueVoiture(String pays) {
        this.pays = pays;
    }

    public String getPays() {
        return pays;
    }

    @Override
    public String toString() {
        return this.name() + " (" + pays + ")";
    }
}

Règles importantes :

  • Les constantes énumérées doivent être déclarées en premier, suivies d'un point-virgule.
  • Chaque constante appelle un constructeur correspondant (ici un constructeur à un paramètre).
  • Si le constructeur est sans paramètre, les parenthèses peuvent être omises.
  • La classe enum hérite implicitement de java.lang.Enum et est final.

1.4 Méthodes courantes de l'énumération

  • name() : retourne le nom exact de la constante (ex: "BMW").
  • ordinal() : retourne l'indice (0, 1, 2...).
  • values() : retourne un tableau de toutes les constantes.
  • valueOf(String) : convertit une chaîne en constante (lève une exception si la chaîne ne correspond pas).
  • compareTo(Enum) : compare les indices ordinaux.
public class TestEnum {
    public static void main(String[] args) {
        MarqueVoiture[] marques = MarqueVoiture.values();
        for (MarqueVoiture m : marques) {
            System.out.println(m + " ordinal=" + m.ordinal());
        }
        System.out.println(MarqueVoiture.valueOf("BMW")); // BMW (Allemagne)
        System.out.println(MarqueVoiture.BMW.compareTo(MarqueVoiture.AUDI)); // -1
    }
}

1.5 Implémentation d'interfaces avec une énumération

Une énumération peut implémenter une ou plusieurs interfaces, comme une classe normale. Elle ne peut pas hériter d'une autre classe (héritage unique d'Enum).

interface Constructible {
    String description();
}

enum MarqueVoiture implements Constructible {
    BMW("Allemagne") {
        @Override
        public String description() {
            return "Fabricant allemand de voitures de luxe";
        }
    },
    TOYOTA("Japon") {
        @Override
        public String description() {
            return "Fabricant japonais, leader mondial";
        }
    };

    private String pays;

    private MarqueVoiture(String pays) {
        this.pays = pays;
    }

    public String getPays() {
        return pays;
    }
}

  1. Annotations (Annotations)

2.1 Qu'est-ce qu'une annotation ?

Une annotation (@Annotation) est un métadonnée intégrée dans le code source. Elle peut être lue par le compilateur, l'outil de build ou au runtime. Elle ne modifie pas la logique, mais ajoute des informations.

2.2 Annotations standards en Java SE

  • @Override : indique qu'une méthode redéfinit une méthode de la superclasse. Vérifié par le compilateur.
  • @Deprecated : marque un élément comme obsolète (déprécié).
  • @SuppressWarnings : supprime les avertissements du compilateur.

2.3 @Override

class Vehicule {
    public void demarrer() {
        System.out.println("Véhicule démarre");
    }
}

class Voiture extends Vehicule {
    @Override
    public void demarrer() {
        System.out.println("Voiture démarre");
    }

    // Erreur si @Override sur une méthode qui n'existe pas dans la superclasse
    // @Override
    // public void avancer() { } // compilation error
}

Si @Override est présent, le compilateur vérifie que la méthode remplace effectivement une méthode parente. Sinon, erreur.

2.4 @Deprecated

class AncienProgramme {
    @Deprecated
    public void vieilleMethode() {
        System.out.println("Ancienne méthode, déconseillée");
    }

    public void nouvelleMethode() {
        System.out.println("Nouvelle méthode recommandée");
    }
}

L'annotation @Deprecated n'empêche pas l'utilisation, mais génère un avertisesment. Elle facilite la transition entre versions.

2.5 @SuppressWarnings

Permet de supprimer des avertissements spécifiques. Par exemple, pour ignorer les avertissements liés aux types bruts (rwatypes), aux éléments inutilisés, etc.

import java.util.ArrayList;
import java.util.List;

public class ExempleSuppress {
    @SuppressWarnings("unchecked")
    public static void main(String[] args) {
        List list = new ArrayList(); // raw type warning
        list.add("hello");
    }

    @SuppressWarnings("deprecation")
    public void utiliserAncien() {
        AncienProgramme prog = new AncienProgramme();
        prog.vieilleMethode(); // warning supprimé
    }
}

Les valeurs courantes : "all", "unchecked", "deprecation", "rawtypes", "unused", etc.

2.6 Méta-annotations

Les méta-annotations sont des annotations qui s'appliquent à d'autres annotations :

  • @Retention : indique si l'annotation est présente dans le code source, le fichier class ou au runtime (SOURCE, CLASS, RUNTIME).
  • @Target : spécifie sur quels éléments (méthode, classe, champ, etc.) l'annotation peut être appliquée.
  • @Documented : l'annotation apparaît dans la documentation Javadoc.
  • @Inherited : l'annotation est héritée par les sous-classes.

Exemple de définition d'une annotation personnalisée :

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MonAnnotation {
    String valeur() default "defaut";
}

Étiquettes: Java énumération Annotation Enum Override

Publié le 6 septembre à 16h02