- É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.Enumet estfinal.
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;
}
}
- 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";
}