Blog ENI : Toute la veille numérique !
🐠 -25€ dès 75€ 
+ 7 jours d'accès à la Bibliothèque Numérique ENI. Cliquez ici
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
  1. Livres et vidéos
  2. Apprendre la Programmation Orientée Objet avec le langage Java
  3. Création de classes
Extrait - Apprendre la Programmation Orientée Objet avec le langage Java (avec exercices pratiques et corrigés) (3e édition)
Extraits du livre
Apprendre la Programmation Orientée Objet avec le langage Java (avec exercices pratiques et corrigés) (3e édition) Revenir à la page d'achat du livre

Création de classes

Introduction

Rappelons qu’une classe est un modèle que le système utilise pour instancier l’objet correspondant en mémoire. Ce sont ces modèles que le développeur déclare dans, ce qui est communément appelé, les fichiers sources (fichiers d’extension .java) de son projet. C’est ce que nous venons de faire dans l’exercice LabTypesJava avec la classe Main.

Package

Les classes Java sont regroupées par finalités dans des ensembles appelés packages eux-mêmes organisés sous forme hiérarchique. Quand vous rédigez le code source et que vous souhaitez utiliser une classe d’un package donné il vous faut soit préciser son "chemin complet" à chaque appel ou, de façon plus concise, déclarer son importation dans l’en-tête du fichier source. Les classes "standard" du package java.lang ne suivent pas cette règle ; elles sont directement accessibles !

Les classes que vous allez développer devront obligatoirement appartenir à des packages que vous allez donc devoir créer. L’organisation de ces ensembles de classes et de leurs hiérarchies vous permet de contrôler la "portée" des packages, des classes et des méthodes.

Il existe des conventions de nommage pour les packages (comme d’ailleurs pour les classes, les méthodes, etc.). Celles-ci peuvent varier d’une entreprise à l’autre. Généralement le package commence par le nom d’un type de domaine (com, edu, gov, mil, net, org) suivi par un point (.) suivi par le nom de la société lui-même suivi par un point (.). Ensuite, il peut y avoir un nom de projet ou de module utilisable dans plusieurs projets, etc.

Exemple de nom de package

com.eni.facturation.exportcompta

Choisissez des noms...

Déclaration d’une classe

Une fois le package déclaré, la classe peut être définie après d’éventuelles lignes d’importation.

Il n’est pas possible de déclarer plus d’une classe dans le même fichier source sauf si elles sont "imbriquées" ou si les classes sont "privées" au fichier source qui les contient.

Si vous essayez de déclarer deux classes de type public dans un même fichier source, IntelliJ IDEA réagira comme suit :

images/05RI10V3.png

Une classe se déclare avec le mot-clé class suivi par le nom que vous lui avez choisi. Comme pour le package, ce nom doit commencer par une lettre ou par un tiret bas (_). Il peut ensuite contenir des lettres, des chiffres et des tirets bas. Évitez d’utiliser les caractères accentués et optez pour une convention de nommage de type Pascal Case. Par exemple, si vous écrivez une classe émulant un lecteur numérique, le nom au format "PascalCase" sera LecteurNumerique. Les premières lettres des mots liés sont en majuscules.

Expliquée en détails plus loin, la déclaration d’un héritage éventuel intervient ensuite. En effet si la classe "étend" une classe existante alors le mot-clé extends précède le nom de la superclasse.

Si la classe "implémente" une ou plusieurs interfaces alors le mot-clé implements précède la liste des interfaces supportées par la classe.

Les membres de la classe (les attributs et les méthodes) sont ensuite définis entre accolades.

Syntaxe de déclaration

visibilité class NomClass  [[extends ClasseMere] 
[implements Liste interfaces de base]] 
{ 
   // corps de la classe 
} 

Exemple

package com.masociete; 
 
public class ClasseHeritiaire extends SaClasseMere implements 
Interface1, Interface2 { 
   // Corps de la classe 
} 

L’attribut de visibilité d’une classe définie dans un package peut être de type :

  • public : la classe sera utilisable par tous.

  • <aucune définition> : la classe sera accessible par les classes du package dans lequel elle se trouve.

Les autres attributs (private, protected) n’ont...

Les interfaces

1. Introduction

Expliquer les interfaces et leurs intérêts est toujours plus convaincant avec un exemple concret à l’appui... Alors, imaginons un programme permettant de piloter un système domotique depuis un téléphone portable (avec nos smartphones toujours connectés, l’engouement pour ce type d’application explose !). Ce programme graphique permettra de commander des volets électriques, lire des températures, démarrer un four... Bref, lire et écrire des états logiques (vrai ou faux) et lire et écrire des valeurs analogiques (00 à ff par exemple).

Dans ce genre d’applications, il faut veiller à ne pas être lié à un matériel précis. Un changement de la carte entrées/sorties - c’est-à-dire la carte qui va lire les capteurs et piloter les relais commandant les équipements - doit impacter le moins possible le code existant.

C’est là que les interfaces de programmation vont nous aider...

2. Le contrat

Pour réussir notre indépendance vis-à-vis du matériel, il faut limiter ses liens à leurs plus simples expressions et les "contractualiser".

Par analogie on peut dire que c’est grâce à la prise "au format standard Connecteur Jack 3.5mm stéréo" que n’importe quel casque audio peut se connecter à n’importe quel baladeur numérique. Cette fameuse prise joue le rôle d’interface entre deux matériels qui ne sont pas obligatoirement issus du même constructeur.

Limiter les liens à leurs plus simples expressions revient à lister les fonctionnalités minimales attendues pour la carte d’entrées/sorties. Cette liste est une sorte de contrat que devra obligatoirement respecter le matériel. Pour reprendre l’analogie précédente, les fabricants de casques audio proposent des produits avec des connecteurs de liaison aux diamètres normalisés et c’est par cette "interface" que l’interconnexion devient possible.

Alors, pour ce projet domotique, quels sont nos besoins ?

Il faut pouvoir :

  • lire des états binaires sur des entrées référencées : interrupteurs, poussoirs, capteurs de présences,

  • lire...

Associations, compositions et agrégations

Dans tout programme, le développeur est amené à concevoir des classes qui utilisent ou contiennent d’autres classes pouvant à leur tour utiliser ou contenir d’autres classes, etc. Par exemple, un formulaire (boîte de dialogue avec l’utilisateur) affiche différents contrôles comme des boutons radio, des cases à cocher, des boîtes de saisie de texte ou autres listes déroulantes. Le formulaire et chacun de ses contrôles sont "encapsulés" dans des classes que le développeur va associer pour parvenir à l’affichage de la boîte finale.

Les associations sont plus ou moins fortes. Dans notre exemple l’association est forte car c’est le formulaire qui instancie ces contrôles et ces mêmes contrôles seront détruits à sa fermeture. On parle alors d’agrégation "composite" ou plus simplement de "composition".

Pendant cette association l’objet Contenant accède librement aux membres de type public de chacun des objets Contenu. Ainsi, lors de son chargement, notre formulaire pourra initialiser les contenus par défaut des boîtes texte, les sélections des boutons radio et, au moment de la validation, récupérer les choix de l’utilisateur en interrogeant chacun des contrôles.

Comment le langage Java permet-il de gérer ces différentes formes de collaboration ?

Quel que soit le degré d’association, la classe Contenant aura besoin de stocker des références sur les classes "contenues".

Il peut y avoir plusieurs objets de mêmes types référencés dans la classe Contenant. Cette pluralité s’exprime d’ailleurs en UML par un indice au bout de la liaison indiquant soit une quantité finie soit une fourchette possible.

images/05RI08.png

Dans cet exemple, un auteur peut écrire un ou un nombre indéfini d’ouvrages (1..*) et un ouvrage n’est rattaché qu’à un seul auteur (1).

Le langage Java va donc avoir plusieurs formes de codages pour ces différents types d’association.

  • La classe Contenant contient une simple référence à un objet de type Contenu

class Contenant{ 
   Contenu contenu...

Les classes imbriquées

Il est possible de déclarer une classe... dans une classe ! Cette fonctionnalité offre au développeur une façon supplémentaire d’organiser son code. Les classes principales sont enregistrées dans des packages et il est donc possible d’effectuer des regroupements à l’intérieur de ces classes principales.

La plupart du temps, la classe imbriquée - appelée nested class ou inner class - n’a aucune signification en dehors de sa classe hôte et son opérateur de visibilité est de type private. Il est malgré tout possible de modifier ce type d’accès en public, protected ou package private.

Syntaxe d’une nested class

public class ClasseHote { 
    
    class ClasseImbriquee { 
 
    } 
    //... 
} 

La classe imbriquée a accès à tous les membres de la classe hôte. La classe hôte a accès à tous les membres de la classe imbriquée.

Le fait de déclarer une classe dans une autre n’implique absolument pas une quelconque instanciation automatique de la classe imbriquée au moment de l’instanciation de la classe hôte. Cela reste une déclaration.

La classe imbriquée peut être de type static et dans ce cas est communément appelée static nested class.

Si la classe imbriquée n’est pas de type static elle est appelée inner class.

Exemple de codage d’une classe imbriquée et de sa classe hôte

package com.eni; 
 
public...

Quelques différences avec le C#

Les langages Java et C# sont très proches. Ce sont tous les deux des langages de références (au sens propre et au sens figuré) et le passage de l’un à l’autre ne posera pas de gros problèmes.

Si vous êtes développeur C# les différences à savoir concernant ce chapitre sont que Java ne supporte pas :

  • Les structures : héritage du C, les structures sont très proches des classes en C#. La principale différence concerne la mémoire dans laquelle elles sont stockées. Les classes sont écrites sur le tas (heap) et les structures sont sur la pile (stack) donc très rapides d’accès car déclarées par le compilateur, elles ne nécessitent aucune allocation du système d’exploitation.

  • Les classes partielles (définies dans plusieurs fichiers sources)  : c’est un bien, diront certains.

  • Les méthodes partielles qui ont leurs signatures définies dans un fichier source et leurs implémentations (optionnelles) définies dans un autre : même remarque.

  • La surcharge d’opérateurs et notamment les [] représentant des indexeurs ou encore le == permettant de tester l’égalité entre deux objets. Il est vrai que la surcharge d’opérateurs étant optionnelle, l’utilisateur...