Programmation Orientée Objet Avancée en Java

Variables de classe (statiques)

Pourquoi les variables de classe statiques sont-elles nécessaires ?

Prenons l'exemple d'une entreprise qui distribue des cadeaux. Afin de suivre le nombre d'employés ayant reçu leur cadeau, on utilise une variable de classe partagée entre toutes les instances de la classe Cadeau.


public class DistributionCadeaux {
    public static void main(String[] args) {
        Cadeau employe1 = new Cadeau("Alice");
        Cadeau employe2 = new Cadeau("Bob");

        employe1.recevoir();
        System.out.println("Cadeaux distribués : " + Cadeau.nombreReceveurs + " employés : " + Cadeau.listeNoms);

        employe2.recevoir();
        System.out.println("Cadeaux distribués : " + employe2.nombreReceveurs + " employés : " + Cadeau.listeNoms);
    }
}

class Cadeau {
    private String nomEmploye;
    protected static int nombreReceveurs = 0;
    public static String listeNoms = "";

    public Cadeau(String nom) {
        this.nomEmploye = nom;
    }

    public void recevoir() {
        if (nombreReceveurs > 5) {
            Cadeau.nombreReceveurs = 0;
        }
        nombreReceveurs++;
        listeNoms += this.nomEmploye;
    }
}

Résultat : Cadeaux distribués : 1 employés : Alice Cadeaux distribués : 2 employés : AliceBob

Quand utiliser une variable de classe ? Lorsque des données doivent être partagées entre toutes les instances d'une classe, indépendamment des objets individuels.

Définition : public static int compteur; (format recommandé)

Utilisation : NomDeLaClasse.compteur (accès privilégié via le nom de la classe)

Méthodes statiques

Les méthodes statiques opèrent sur des données de classe et ne nécessitent pas d'instance.


public class CalculFrais {
    public static void main(String[] args) {
        CalculFrais.ajouterFrais(3000.0);
        CalculFrais.ajouterFrais(5000.0);
        System.out.println("Total des frais : " + CalculFrais.obtenirTotal() + " euros");
    }

    private static double totalFrais = 0;

    public static void ajouterFrais(double montant) {
        totalFrais += montant;
    }

    public static double obtenirTotal() {
        return totalFrais;
    }
}

Résultat : Total des frais : 8000.0 euros

Points importants : les méthodes statiques ne peuvent utiliser this ou super. Elles ne peuvent accéder qu'aux membres statiques de la clasce.

La méthode main

Signature : public static void main(String[] args)

La méthode doit être publique pour être appelée par la JVM, statique pour ne pas nécessiter d'instance, et accepte des arguments sous forme de tableau de chaînes.

Blocs de code

Blocs d'initialisation et blocs statiques ont des ordres d'exécution différents.


public class InitialisationExemple {
    public static void main(String[] args) {
        new ClasseDerivee();
    }
}

class ClasseBase {
    static {
        System.out.println("Bloc statique ClasseBase");
    }
    {
        System.out.println("Bloc d'instance ClasseBase");
    }
    public ClasseBase() {
        System.out.println("Constructeur ClasseBase");
    }
}

class ClasseDerivee extends ClasseBase {
    static {
        System.out.println("Bloc statique ClasseDerivee");
    }
    {
        System.out.println("Bloc d'instance ClasseDerivee");
    }
    public ClasseDerivee() {
        System.out.println("Constructeur ClasseDerivee");
    }
}

Résultat d'exécution : Bloc statique ClasseBase Bloc statique ClasseDerivee Bloc d'instance ClasseBase Constructeur ClasseBase Bloc d'instacne ClasseDerivee Constructeur ClasseDerivee

Modèle Singleton

Assure qu'une classe n'a qu'une seule instance.


public class SingletonExemple {
    private static SingletonExemple instance;
    private String etat;

    private SingletonExemple(String etat) {
        this.etat = etat;
    }

    public static SingletonExemple obtenirInstance(String etat) {
        if (instance == null) {
            instance = new SingletonExemple(etat);
        }
        return instance;
    }
}

Classes abstraites

Une classe abstraite peut contenir des méthodes abstraites et concrètes. Elle sert de modèle pour les sous-classes.


public abstract class FormeAbstraite {
    public abstract double calculerAire();

    public void afficherAire() {
        System.out.println("Aire : " + calculerAire());
    }
}

class CercleConcret extends FormeAbstraite {
    private double rayon;

    public CercleConcret(double r) {
        this.rayon = r;
    }

    @Override
    public double calculerAire() {
        return Math.PI * rayon * rayon;
    }
}

Design Pattern Template Method

La classe abstraite définit le squelette d'un algorithme, laissant les étapes spécifiques aux sous-classes.


public abstract class ModeleTraitement {
    public final void executer() {
        etape1();
        etape2Specifique();
        etape3();
    }

    protected abstract void etape2Specifique();

    private void etape1() {
        System.out.println("Étape 1 commune");
    }

    private void etape3() {
        System.out.println("Étape 3 commune");
    }
}

Interfaces

Définissent un contrat que les classes doivent respecter.


public interface Serialisable {
    void serialiser();
    void deserialiser();
}

class Document implements Serialisable {
    @Override
    public void serialiser() {
        System.out.println("Sérialisation en cours");
    }

    @Override
    public void deserialiser() {
        System.out.println("Désérialisation en cours");
    }
}

Dans Java 8+, les interfaces peuvent contenir des méthodes par défaut et statiques.

Polymorphisme et Interfaces

Les références d'interface peuvent pointer vers des instances de classes implémentant cette interface.


public class TestInterface {
    public static void main(String[] args) {
        Serialisable[] elements = { new Document(), new Image() };
        for (Serialisable elem : elements) {
            elem.serialiser();
        }
    }
}

Classes internes

Classe interne anonyme

Souvent utilisée pour implémenter des interfaces ou des classes abstraites de manière concise.


public class ExempleAnonyme {
    public void executerAction(Action action) {
        action.effectuer();
    }

    public static void main(String[] args) {
        ExempleAnonyme exemple = new ExempleAnonyme();
        exemple.executerAction(new Action() {
            @Override
            public void effectuer() {
                System.out.println("Action anonyme exécutée");
            }
        });
    }
}

interface Action {
    void effectuer();
}

Classe interne statique

Ne nécessite pas de référence à l'instance de la classe englobante.


public class ClasseEnglobante {
    private static int valeurStatique = 10;

    static class ClasseInterneStatique {
        public void afficher() {
            System.out.println("Valeur statique : " + valeurStatique);
        }
    }
}

Annotations

@Override : indique une redéfinition de méthode.

@Deprecated : marque un élément comme obsolète.

@SuppressWarnings : supprime certains avertissements du compilatuer.

Classes enveloppantes

Permettent de manipuler les types primitifs comme des objets. Exemples : Integer, Double, Boolean.


public class ExempleEnveloppant {
    public static void main(String[] args) {
        Integer nombreObjet = Integer.valueOf(42);
        int nombrePrimitif = nombreObjet.intValue();
        String enTexte = nombreObjet.toString();
    }
}

Étiquettes: Java Programmation-Orientée-Objet classes-abstraites interfaces classes-internes

Publié le 31 juillet à 20h00