 |
-- Main.bassim - 02 Jul 2008
Concepts de la programmation Orientée Objet
Si vous n'avez jamais employé un langage de programmation orienté objet auparavant, vous aurez besoin d'apprendre quelques concepts de base avant que vous puissiez commencer à écrire n'importe quel code. Cette leçon vous présentera ce que sont les objets, les classes, l'héritage, les interfaces, et les packages. Chaque paragraphe se concentrera sur la façon dont ces concepts se relient à la réalité, tout en fournissant une introduction à la syntaxe du langage de programmation Java.
Qu'est ce qu'un Objet ?
Un objet est un ensemble de briques logiciels caractérisé par un état et un comportement . Les objets sont souvent employés pour modéliser les objets réels que vous trouvez dans la vie quotidienne. Cette leçon explique comment l'état et le comportement sont représentés dans un objet, présente le concept de l'encapsulation des données, et explique les avantages à concevoir votre logiciel de cette manière.
Les objets sont essentiels à la compréhension de la technologie Orientée Objet. Regardez autour de vous et vous trouverez beaucoup d'exemples d'objets réels : votre chien, votre bureau, votre téléviseur, votre bicyclette.
les objets de la vie réelle partagent deux caractéristiques : ils ont tous un état et un comportement. Les chiens ont un état (le nom, couleur, race, affamé) et un comportement (aboiements, nettoyage, remuer sa queue). Les bicyclettes ont également un état (vitesse , cadence de pédale, marque) et un comportement (accélérer , freiner, évolution). Identifier l'état et le comportement des objets du monde réel est une excellente façon de commencer à penser en terme de la programmation Orientée Objet.
Prenez une minute pour observer les objets du monde réel qui se trouvent dans votre voisinage immédiat. Pour chaque objet que vous voyez, posez-vous deux questions: ''Quels sont les états possibles que peut avoir cet objet ?'' Et ''Quel comportement peut avoir cet objet?''. Assurez-vous d'écrire vos observations. vous remarquez que les objets du monde réel varient en complexité; votre lampe de bureau peut avoir que deux états possibles (on et off) et deux comportements possibles (allumer, éteindre), mais la radio peut avoir des états supplémentaires (on, off, le volume actuel, la station actuelle) et des comportements (allumer, éteindre, augmenter le volume, diminuer le volume, rechercher, numérisation et de l'écoute). Vous remarquerez également que certains objets, contiendront à leur tour d'autres objets. Ces observations du monde réel peuvent être transcrits vers des objets de la programmation Orientée Objet.
http://java.sun.com/docs/books/tutorial/figures/java/concepts-object.gif
_Objet informatique_
Les objets informatiques sont conceptuellement similaires aux objets du monde réel: ils se constituent aussi d'un état et de comportements y afférents. Un objet stocke son état dans les champs (variables dans certains langages de programmation) et expose son comportement par des méthodes (fonctions dans certains langages de programmation). Les méthodes opèrent sur l'état interne d'un objet et servent de mécanisme de base pour une communication objet à objet. Cacher l'état interne et recourir aux méthodes pour interagir avec un objet quelconque est connu sous le nom de l'_encapsulation_ des données - un principe fondamental de la programmation orientée objet.
Prenez une bicyclette, par exemple:
http://java.sun.com/docs/books/tutorial/figures/java/concepts-bicycleObject.gif
bicyclette modélisée en un objet informatique
En attribuant un état (vitesse actuelle, la cadence de pédale actuelle , et la vitesse du boitier actuelle) et en fournissant des méthodes pour modifier cet état, l'objet contrôle la manière dont le monde extérieur est autorisé à l'utiliser. Par exemple, si le vélo ne dispose que de 6 vitesses, une méthode permettant de changer de vitesse pourrait refuser toute valeur inférieure à 1 ou supérieure à 6.
Ecrire le code sous forme d'objets individuels fournit un certain nombre d'avantages, notamment:
- Modularité : Le code source d'un objet peut être écrit et maintenu indépendamment du code source des autres objets. Une fois créé, un objet peut être facilement passée à l'intérieur du système.
- Encapsulation des données : en interagissant seulement avec les méthodes d'un objet, les détails de son implémentation interne restent cachés au monde extérieur.
- Réutilisation du code : Si un objet existe déjà (peut-être écrit par un autre développeur de logiciel), vous pouvez utiliser cet objet dans votre programme. Cela permet aux spécialistes de implémenter / tester / déboguer (complexes, les tâches spécifiques des objets), que vous pourrez ensuite intégrer dans votre propre code.
- Pluggability et facilité de débogage : Si un objet particulier s'avère problématique, vous pouvez simplement le supprimer de votre application et intégrer un autre objet comme remplaçant. Cela se compare à la détermination des problèmes mécaniques dans le monde réel. Si un boulon casse, vous le remplacez par un autre boulon, et non pas l'ensemble de la machine.
Qu'est ce qu'une Classe ?
Une classe est un modèle ou un prototype dont des objets sont créés. Cette section définit une classe qui modèle l'état et le comportement d'un objet réel. Elle se concentre intentionnellement sur les fondations, montrant comment même une classe simple peut proprement modeler l'état et le comportement.
Dans le monde réel, vous trouverez souvent de nombreux d'objets tous individus de la même sorte. Il peut y avoir des milliers d'autres bicyclettes existantes, toutes de la même marque et du même modèle. Chaque bicyclette a été construite à partir du même ensemble de modèles et contient donc les mêmes composants.
En terme orienté objet, nous dirons que votre bicyclette est une instance de la classe des objets connus sous le nom de "bicyclettes". Une classe est le modèle à partir duquel différents objets sont créés.
La classe Velo suivante représente une possible implémentation d'une bicyclette:
class Velo {
int cadence = 0;
int speed = 0;
int gear = 1;
void changeCadence(int newValue) {
cadence = newValue;
}
void changeGear(int newValue) {
gear = newValue;
}
void speedUp(int increment) {
speed = speed + increment;
}
void applyBrakes(int decrement) {
speed = speed - decrement;
}
void printStates() {
System.out.println("cadence:"+cadence+" speed:"+speed+" gear:"+gear);
}
}
La syntaxe du langage de programmation Java vous paraitra nouvelle, mais le design de cette classe est basé seulement sur la précédente analyse des objets bicyclettes. Les champs cadence, vitesse et Gear représentent l'état de l'objet, et les méthodes (changeCadence, changeGear, speedUp ...) définissent son interaction avec le monde extérieur.
Vous avez peut-être remarqué que la classe Velo ne contient pas de méthode main. C'est parce que ce n'est pas une application complète, c'est juste le schéma directeur pour les vélos qui pourrait être utilisé dans une application. La responsabilité de créer et d'utiliser de nouveaux objets Velo appartient à une autre classe dans votre application.
Voici la classe VeloDemo qui crée deux objets Velo distincts et invoque leurs méthodes:
class VeloDemo {
public static void main(String[] args) {
// Create two different Bicycle objects
Bicycle bike1 = new Bicycle();
Bicycle bike2 = new Bicycle();
// Invoke methods on those objects
bike1.changeCadence(50);
bike1.speedUp(10);
bike1.changeGear(2);
bike1.printStates();
bike2.changeCadence(50);
bike2.speedUp(10);
bike2.changeGear(2);
bike2.changeCadence(40);
bike2.speedUp(10);
bike2.changeGear(3);
bike2.printStates();
}
}
Le résultat de ce test affiche la dernière cadence de pédale, la vitesse et la gear pour les deux vélos:
cadence:50 speed:10 gear:2
cadence:40 speed:20 gear:3
Qu'est ce que l'héritage ?
L'*héritage* fournit un mécanisme puissant et naturel pour organiser et structurer votre logiciel. Cette section explique comment les classes héritent de l'état et du comportement de leurs superclasses, et explique comment dériver une classe des autres en employant une syntaxe simple fournie par le langage de programmation Java.
Les différents types d'objets ont souvent en commun un certain nombre de choses entre eux. Les vélos de montagne, les vélos de route, et les vélos tandem, par exemple, tous partagent les caractéristiques des bicyclettes (vitesse courante, cadence courante de pédale, vitesse courante). Pourtant chacun définit également des caractéristiques additionnelles qui les rendent différents : les bicyclettes tandem ont deux sièges et deux ensembles de guidons ; les vélos de route ont des guidons de baisse ; quelques vélos de montagne ont un anneau à chaînes additionnel, leur donnant un rapport inférieur de vitesse.
La programmation Orientée Objet permet aux classes d'_hériter_ les états et les comportements couramment utilisés dans d'autres classes.
Dans cet exemple, Velo devient maintenant une superclasse de MountainBike?, RoadBike? et TandemBike?. Dans le langage de programmation Java, chaque classe est autorisée à avoir une superclasse directe, et chaque superclasse a le potentiel d'avoir un nombre illimité de sous-classes :
http://java.sun.com/docs/books/tutorial/figures/java/concepts-bikeHeirarchy.gif
La hiérarichie de classes de la classe Velo (Bicycle)
La syntaxe pour créer une sous-classe est simple. Au début de votre déclaration de classe, utilisez le mot-clé extends, suivi par le nom de la classe à hériter :
class MountainBike extends Bicycle {
// new fields and methods defining a mountain bike would go here
}
Cela donne à MountainBike tout les champs et les méthodes de Velo, mais son code permet de se concentrer exclusivement sur les caractéristiques qui la rend unique. Cela rend le code de votre sous-classe facile à lire. Toutefois, vous devez prendre soin de bien documenter l'état et le comportement que chaque superclasse définit, dans la mesure où ce code ne s'affiche pas dans le fichier source de chaque sous-classe.
Qu'est ce qu'une Interface ?
Une interface est un contrat entre une classe et le monde extérieur. Quand une classe implémente une interface, elle promet de fournir le comportement (édité) par cette interface. Cette section définit une interface simple et explique les changements nécessaires que doit faire n'importe quelle classe qui l'implémente.
Comme vous avez déjà appris, les objets définissent leur interaction avec le monde extérieur par les méthodes qu'ils exposent. Les méthodes forment l'_interface_ des objets avec le monde extérieur ; les boutons sur l'avant de votre téléviseur, par exemple, sont une interface entre vous et le câblage électrique de l'autre côté de son boitier en plastique. Vous pressez le bouton On/Off pour allumer ou éteindre la télévision.
Dans sa forme la plus courante, une interface est un ensemble de méthodes (connexes) avec un corps vide. Le comportement d'un Velo, s'il est défini par une interface, pourrait ressembler à ça:
interface Velo {
void changeCadence(int newValue);
void changeGear(int newValue);
void speedUp(int increment);
void applyBrakes(int decrement);
}
Pour implémenter cette interface, le nom de votre classe doit changer (en ACMEBicycle, par exemple), et vous utiliserez le mot-clé implements dans la déclaration de votre classe:
class ACMEBicycle implements Bicycle {
// remainder of this class implemented as before
}
Implémenter une interface permet à une classe de devenir plus formelle sur le comportement qu'elle promet d'apporter. les interfaces forment un contrat entre la classe et le monde extérieur, et ce contrat est appliquée à la compilation par le compilateur. Si votre classe prévoit d'implémenter une interface, toutes les méthodes définies par celle ci doivent apparaitre dans le code source avant que la classe ne se compile correctement.
Qu'est ce qu'un Package ?
Un package (paquet) est un namespace pour les classes et les interfaces d'organisation d'une façon logique. Le placement de votre code dans des paquets facilite de grands projets de logiciel pour contrôler. Cette section explique pourquoi c'est utile, et vous présente à l'interface de programmation d'application (api) fournie par la plateforme de Java.
Un package est un espace de nom qui organise un ensemble de classes et d'interfaces (similaires). Conceptuellement vous pouvez comprendre les packages comme les différents dossiers se trouvant sur votre ordinateur. Vous pourriez rassembler des pages HTML dans un seul dossier, les images dans un autre, et les scripts ou les applications dans un autre encore. Puisque un logiciel écrit en Java peut se composer de centaines ou de milliers de différentes classes, il est normal de maintenir les choses bien organisées, en plaçant les classes et les interfaces reliées dans des packages.
La plate-forme Java fournit une énorme bibliothèque de classes (un ensemble de packages) adaptée pour une utilisation dans vos propres applications. Cette bibliothèque est connue sous le nom de Application Programming Interface, ou API pour être plus court. (Ses packages représentent les tâches les plus couramment associés à des fins générales de programmation). Par exemple, un objet String contient l'état et le comportement des chaînes de caractères, un objet File permet au programmeur de facilement créer, supprimer, rechercher, comparer, modifier un fichier sur le système de fichiers, un objet Socket permet la création et l'utilisation des sockets réseau ; les différents objets GUI ;les boutons de contrôle et de cases à cocher et de toute autre chose liés à des interfaces utilisateur graphiques. Il y a littéralement des milliers de classes à choisir.
Cela permet au programmeur, de se concentrer sur la conception d'une application particulière, plutôt que de l'infrastructure nécessaire pour la faire fonctionner.
La [http://java.sun.com/javase/6/docs/api/index.html Java plate-forme API Specification] contient la liste complète de tous les packages, les interfaces, les classes, les champs et les méthodes fournies par la plate-forme Java 6 Standard Edition. Chargez la page dans votre navigateur et mettez dans vos favoris. En tant que programmeur, elle sera votre seule et importante documentation de référence.
Les bases du langage (non traduit)
Les Classes et les Objets
Décrit la manière d'écrire des classes à partir desquelles les objets seront créés, et comment créer et utiliser ces objets.
Avec les connaissances que vous avez acquises sur les bases du langage, vous pouvez apprendre maintenant à écrire vos propres classes. Dans cette leçon, vous trouverez des informations sur la définition de vos propres classes, y compris la déclaration des variables(ou attributs) membres, des méthodes, et des constructeurs.
Vous apprendrez à utiliser vos classes pour créer vos objets et comment les utiliser.
La leçon traitera aussi des classes internes à d'autres classes, les énumérations, et les annotations.
Les Classes
Cette section vous montrera l'anatomie d'une classe, et comment déclarer les champs, les méthodes, et les constructeurs.
L'introduction aux concepts orientés objets dans le cadre du cours intitulé [http://it.dzfac.com/wiki/index.php?title=Apprendre_le_langage_Java#Concepts_de_la_programmation_Orient.C3.A9e_Objet Concepts de la programmation Orientée Objet] utilisait la classe Velo à titre d'exemple, et comme sous-classes, des vélos de course, VTT, vélos tandem. Voici des exemples de code pour une éventuelle implémentation de la classe Velo, ceci afin de vous donner un aperçu sur la déclaration d'une classe. Les sections de la leçon qui viendra vous expliquera la déclaration d'une classe étape par étape. Pour l'instant, ne vous attardez pas sur les détails.
public class Bicycle {
// '''the Bicycle class has three fields'''
public int cadence;
public int gear;
public int speed;
// '''the Bicycle class has one constructor'''
public Bicycle(int startCadence, int startSpeed, int startGear) {
gear = startGear;
cadence = startCadence;
speed = startSpeed;
}
// '''the Bicycle class has four methods'''
public void setCadence(int newValue) {
cadence = newValue;
}
public void setGear(int newValue) {
gear = newValue;
}
public void applyBrake(int decrement) {
speed -= decrement;
}
public void speedUp(int increment) {
speed += increment;
}
}
La déclaration de la classe MountainBike? qui est une sous-classe de Velo pourrait ressembler à ça:
public class MountainBike extends Bicycle {
// '''the MountainBike subclass has one field'''
public int seatHeight;
// '''the MountainBike subclass has one constructor'''
public MountainBike(int startHeight, int startCadence, int startSpeed, int startGear) {
super(startCadence, startSpeed, startGear);
seatHeight = startHeight;
}
// '''the MountainBike subclass has one method'''
public void setHeight(int newValue) {
seatHeight = newValue;
}
}
MountainBike? hérite de tout les membres et les méthodes de la classe Velo, et ajoute le champ seatHeight et une méthode pour l'initialiser(les VTT ont des sièges qui peuvent être déplacés de haut en bas comme l'exige le relief).
Déclarer des Classes
Vous avez vu qu'une classe est définie de cette façon:
class ''MyClass'' {
//field, constructor, and method declarations
}
Il s'agit de la ''déclaration d'une classe''. le ''corps de la classe'' (l'espace entre les deux accolades) contient tout le code prévu pour le cycle de vie des objets créés à partir de cette classe: les constructeurs pour initialiser les nouveaux objets, les déclarations des champs qui fournissent l'état d'une classe et de ses objets, les méthodes qui définissent le comportement de la classe et de ses objets.
La déclaration précédente d'une classe est le minimum que peut contenir une classe. Vous pouvez ajouter d'autres informations à votre classe, comme le nom de sa classe mère, si elle implémente des interfaces, et ainsi de suite, au début de la déclaration. Par exemple:
''class MyClass extends MySuperClass implements YourInterface'' {
//field, constructor, and method declarations
}
signifie que MyClass? est une sous-classe de MySuperClass? et qu'elle implémente l'interface ''YourInterface''
Vous pouvez également ajouter des modificateurs comme public ou private, tout au début (et comme vous pouvez le voir, le début d'une ligne de déclaration d'une classe peut devenir très compliquée ). Les modificateurs public et private, qui déterminent quelles autres classes peuvent accéder à MyClass?, seront abordés plus loin dans cette leçon. La leçon sur les interfaces et l'héritage expliquera comment et pourquoi vous devriez utiliser les mots-clés extends et implements dans une déclaration de classe. Pour l'instant vous n'avez pas besoin de vous préoccuper de ces complications supplémentaires.
En général, la déclaration de classes peut inclure dans l'ordre les composants suivants:
1- Les modificateurs, tels que public, private, et plusieurs autres que vous rencontrerez plus tard.
2- Le nom de la classe, avec la première lettre en majuscule, par convention.
3- Le nom de la classe parente (superclasse), le cas échéant, précédé par le mot-clé extends. Une classe ne peut étendre (sous-classe) qu'une seule classe parente (pas d'héritage multiple en Java).
4- Une liste d'interfaces séparées par des virgules qui sont implémentées par la classe, le cas échéant, précédé par le mot-clé implements. Une classe peut implémenter plus d'une interface (remplace en quelque sorte le mécanisme de l'héritage multiple).
5- Le corps de classe est entouré par des accolades, {}.
Déclarer des Variables Membres
Il y a plusieurs genres de variables:
les variables membres dans une classe (appelées les champs).
les variables dans une méthode ou dans un bloc (appelées les variables locales).
les variables dans les déclarations des méthodes (appelées les paramètres).
La classe Velo utilise les lignes de code suivantes pour déclarer ses champs:
public int cadence;
public int gear;
public int speed;
la déclaration des champs est composée dans l'ordre de trois composants:
1- Zéro ou plusieurs modificateurs, tel que public ou private.
2- Le type du champ
3- Le nom du champ
Les champs de la classe Velo sont nommés cadence, gear et speed, et sont tous de type entier (int). Le mot-clé public, identifie ces champs comme des membres publics, donc accessible par n'importe quel objet qui peut acceder à la classe.
Les modificateurs d'accès
Le premier (le plus à gauche) modificateur utilisé permet de contrôler quelles autres classes ont accès à un champ. Pour le moment, retenez uniquement public et private. Les autres modificateurs d'accès seront discutés plus tard.
* Le modificateur public: le champ est accessible à partir de toutes les classes.
* Le modificateur private: le champ est accessible uniquement à l'intérieur de sa classe.
Dans l'esprit de l'encapsulation, il est fréquent de rendre les champs privés. Cela signifie qu'ils ne peuvent être ''directement'' accessibles qu'à partir de la classe Velo. Cependant, on aura toujours besoin d'accéder à ces valeurs. On peut le faire indirectement en ajoutant des méthodes publiques qui obtiennent les valeurs des champs pour nous:
public class Bicycle {
private int cadence;
private int gear;
private int speed;
public Bicycle(int startCadence, int startSpeed, int startGear) {
gear = startGear;
cadence = startCadence;
speed = startSpeed;
}
public int getCadence() {
return cadence;
}
public void setCadence(int newValue) {
cadence = newValue;
}
public int getGear() {
return gear;
}
public void setGear(int newValue) {
gear = newValue;
}
public int getSpeed() {
return speed;
}
public void applyBrake(int decrement) {
speed -= decrement;
}
public void speedUp(int increment) {
speed += increment;
}
}
Les Types
Toutes les variables doivent avoir un type. Vous pouvez utiliser les types primitifs tels que int, char, boolean,… Ou bien, vous pouvez utiliser les types de référence, tels que des chaines de caractères, des tableaux, ou des objets.
Les Noms des variables
Toutes les variables, qu'il s'agisse de champs, de variables locales, ou de paramètres, suivent les mêmes règles de nommage et les mêmes conventions et qui ont fait l'objet d'un cours dans le chapitre les bases du langage, JAVA Naming Conventions?.
Dans cette leçon, sachez que les mêmes règles de nommage et les mêmes conventions sont utilisés pour les méthodes et les noms de classes, excepté ceci:
* La première lettre d'un nom de classe doit être en Majuscule, et
* Le premier (ou le seul) mot dans le nom de la méthode doit être un verbe.
Définir des Méthodes
Voici un exemple d'une déclaration de méthode classique:
public double calculateAnswer(double wingSpan, int numberOfEngines, double length, double grossTons) {
//do the calculation here
}
Les seuls éléments requis lors d'une déclaration d'une méthode sont le type de retour de la méthode, un nom, une paire de parenthèses "()", et un corps entre des accolades "{}".
Plus généralement, les déclarations de méthodes ont six composantes, dans l'ordre:
1. Les modificateurs d'accès, tels que public, private et d'autres que vous apprendrez plus tard.
2. Le type de retour : le type de données de la valeur renvoyée par la méthode, ou ''void'' si la méthode ne retourne aucune valeur.
3. Le nom de la méthode: les règles pour les noms de champ s'appliquent aussi aux noms des méthodes , mais la convention est un peu différente.
4. La liste des paramètres entre parenthèses: une liste de paramètres d'entrée séparés par des virgules, précédés de leurs types de données, entourés par des parenthèses "()". S'il n'y a pas de paramètres, vous devez utiliser des parenthèses vides.
5. Une liste d'exceptions qui seront abordés ultérieurement.
6. Le corps de la méthode , placée entre des accolades: le code de la méthode, et la déclaration des variables locales, se retrouvent ici.
Les modificateurs d'accès, les types de retour, et les paramètres seront discutés plus loin dans cette leçon. Les exceptions seront quand à eux abordées dans une prochaine leçon.
Définition: Deux des composantes d'une déclaration de méthode constituent la signature de la méthode : le nom de la méthode et le type des paramètres.
La signature de la méthode déclarée en haut est:
calculateAnswer(double, int, double, double)
Nommer une méthode
Même si un nom de méthode peut contenir n'importe quel identifiant autorisé, les conventions de code restreignent ces noms là. Par convention, les noms des méthodes doivent être sous forme d'un verbe en minuscules, ou d'un nom en plusieurs mots qui commence par un verbe en minuscules, suivi d'adjectifs, noms, etc. Avec les noms en plusieurs mots, la première lettre de chacun des deuxièmes mots et des suivants devraient être capitalisés. Voici quelques exemples:
run
runFast
getBackground
getFinalData
compareTo
setX
isEmpty
Généralement, une méthode a un nom unique à l'intérieur de sa classe. Toutefois, une méthode peut avoir le même nom que d'autres méthodes grâce à la ''surcharge de méthodes''.
Surcharger les méthodes
Le langage de programmation Java supporte la ''surcharge'' des méthodes, Java peut faire la distinction entre les méthodes à ''signature différente''. Cela signifie que les méthodes d'une classe peuvent avoir le même nom à condition qu'ils aient des listes de paramètre différents (il y a des exceptions à ça qui seront discutées dans la leçon "Interfaces et Héritage").
Supposons que vous ayez une classe qui peut utiliser la calligraphie pour dessiner les divers types de données (chaînes de caractères, les entiers, et ainsi de suite) et qui contient une méthode pour dessiner chaque type de données. Il serait laborieux d'utiliser un nouveau nom pour chaque méthode : par exemple, drawString, drawInteger, drawFloat, et ainsi de suite. Dans le langage de programmation Java, vous pouvez utiliser le même nom pour toutes les méthodes de dessin, à condition de passer une liste d'arguments différents pour chaque méthode. Ainsi, la classe de dessin des données pourrait déclarer quatre méthodes nommés ''draw'', dont chacune a une liste de paramètres différents.
public class DataArtist {
...
public void draw(String s) {
...
}
public void draw(int i) {
...
}
public void draw(double f) {
...
}
public void draw(int i, double f) {
...
}
}
Les méthodes surchargées sont différenciées par le nombre et le type des arguments passés à la méthode. Dans cet échantillon de code, draw(String s) et draw(int i) sont des méthodes distinctes et uniques parce qu'elles ont besoin de différents types d'arguments.
Vous ne pouvez pas déclarer plus d'une méthode avec le même nom et le même nombre et type d'arguments, parce que le compilateur ne pourrait pas les distinguer.
Le compilateur ne prend pas en compte le type de retour lors de la différenciation des méthodes, de sorte que vous ne pouvez pas déclarer deux méthodes avec la même signature, même si elles ont un autre type de retour.
'''Note:''' La surcharge des méthodes doit être utilisée avec modération, car elle peut rendre le code beaucoup moins lisible.
Fournir des Constructeurs pour vos classes
Une classe contient des constructeurs qui sont invoqués pour créer les objets à partir du modèle de la classe. La déclaration des classes ressemble à celle des méthodes à l'exception qu'ils utilisent le nom de la classe et n'ont pas de type de retour. Par exemple, la classe Velo a un seul constructeur:
public Velo (int startCadence, int startSpeed, int startGear) {
gear = startGear;
cadence = startCadence;
speed = startSpeed;
}
Pour créer un nouvel objet de Velo et appelé ''monVelo'', un constructeur est appelé par l'opérateur '''new''' :
Velo monVelo = new Velo(30, 0, 8);
new Velo(30, 0, 8) crée un espace dans la mémoire pour l'objet et initialise ses champs.
même si Velo a uniquement une seule classe, il pourrait en avoir d'autres, y compris un constructeur sans arguments.
public Bicycle() {
gear = 1;
cadence = 10;
speed = 0;
}
Velo tonVelo = new Velo(); appelle le constructeur sans arguments afin de créer un nouvel objet Velo appelé tonVelo.
Les deux constructeurs pourraient avoir été déclaré dans la classe Velo parce qu'ils disposent de listes d'arguments différents. Comme pour les méthodes, la plate-forme Java différencie les constructeurs sur la base du nombre d'arguments dans la liste et leurs types. Vous ne pouvez pas écrire deux constructeurs qui ont le même nombre et le même type d'arguments pour la même classe, parce que la plate-forme ne sera pas en mesure de les distinguer. Ceci provoquerait une erreur à la compilation .
Vous n'êtes pas obligés de fournir des constructeurs pour votre classe, mais vous devez faire attention quand vous le faites. Le compilateur en fournit automatiquement un sans arguments, constructeur par défaut pour toute les classes n'en disposants pas un. Ce constructeur par défaut va appeler le constructeur sans arguments de la superclasse. Dans ce cas, le compilateur se plaindra si la superclasse ne dispose pas d'un constructeur sans arguments, de sorte que vous devriez vérifier que c'est le cas. Si votre classe n'a pas de superclasse explicite, elle aura implicitement comme superclasse la classe Object, laquelle ''dispose'' d'un constructeur sans arguments.
Vous pouvez utiliser un constructeur de la superclasse explicitement. La classe MountainBike? au début de cette leçon le faisait. Cette question sera abordée plus tard, dans la leçon sur les interfaces et l'héritage.
Vous pouvez utiliser les modificateurs d'accès dans une déclaration du constructeur pour contrôler quelles autres classes peuvent appeler le constructeur.
'''Note''': Si une autre classe ne peut pas appeler un constructeur de MyClass?, il ne peut pas créer directement des objets MyClass? .
Passer des informations à une méthode ou à un constructeur
La déclaration d'une méthode ou d'un constructeur déclare le nombre et le type d'arguments pour cette méthode ou constructeur. Par exemple, ce qui suit est une méthode qui calcule les paiements mensuels d'un prêt de logement, sur la base du montant de l'emprunt, le taux d'intérêt, de la durée du prêt (le nombre de périodes), et la valeur future de l'emprunt:
public double computePayment(double loanAmt,
double rate,
double futureValue,
int numPeriods) {
: double interest = rate / 100.0;
: double partial1 = Math.pow((1 + interest), -numPeriods);
: double denominator = (1 - partial1) / interest;
: double answer = (-loanAmt / denominator) - ((futureValue * partial1) / denominator);
: return answer;
}
Cette méthode comporte quatre paramètres: le montant du prêt, le taux d'intérêt, la valeur future et le nombre de périodes. Les trois premiers sont des nombres à virgule flottante en double précision , et le quatrième est un nombre entier. Les paramètres sont utilisés dans le corps de la méthode et au moment de l'exécution prendront les valeurs des arguments qui sont passés à la méthode.
: '''Note:''' Les ''paramètres'' se réfèrent à la liste des variables présentes dans la déclaration d'une méthode . Les ''arguments'' sont les valeurs actuelles qui sont passés lorsque la méthode est invoquée. Lorsque vous invoquez une méthode, les arguments utilisés doivent correspondre aux types des paramètres déclarés dans l'ordre prédéfinis.
Les Types des Paramètres
Vous pouvez utiliser n'importe quel type de données pour un paramètre d'une méthode ou d'un constructeur. Cela comprend les types de données primitifs, comme les doubles, les flottants, et les entiers, comme vous l'avez vu dans la méthode computePayment , et les types de données référencés, comme les objets et tableaux.
Voici un exemple d'une méthode qui accepte un tableau comme argument. Dans cet exemple, la méthode crée un nouvel objet Polygone et l'initialise à partir d'une liste d'objets Point (supposons que la classe Point représente les coordonnées x, y ):
public Polygon polygonFrom(Point[] corners) {
// method body goes here
}
: '''Note:''' Le langage Java ne vous laisse pas passer des méthodes comme arguments d'une méthode.Mais il est possible de passer un objet dans une méthode et ensuite invoquer les méthodes de l'objet .
Nombre arbitraire d'arguments
Vous pouvez utiliser une construction appelée ''varargs'' afin de passer un nombre arbitraire de valeurs à
une méthode. vous utilisez ''Varargs'' quand vous ne savez pas combien d'arguments d'un type particulier seront transmis à la méthode. C'est un raccourci pour créer un tableau manuellement (la méthode précédente aurait pu utiliser varargs plutôt qu'un tableau).
Pour utiliser varargs, vous suivez le type du dernier paramètre par une ellipse (trois points, ...), puis un espace, et le nom du paramètre. La méthode peut ensuite être appelée avec un nombre quelconque de ce paramètre, y compris aucun.
public Polygon polygonFrom(Point... corners) {
int numberOfSides = corners.length;
double squareOfSide1, lengthOfSide1;
squareOfSide1 = (corners[1].x - corners[0].x)*(corners[1].x - corners[0].x)
+ (corners[1].y - corners[0].y)*(corners[1].y - corners[0].y) ;
lengthOfSide1 = Math.sqrt(squareOfSide1);
// more method body code follows that creates
// and returns a polygon connecting the Points
}
Vous voyez que, à l'intérieur de la méthode, corners est traité comme un tableau. La méthode peut être appelé soit avec un tableau ou avec une
séquence d'arguments. Le code dans le corps de la méthode va traiter le paramètre comme un tableau dans les deux cas.
Vous allez voir varargs utilisés souvent avec les méthodes d'impression, par exemple, cette méthode printf:
Public PrintStream printf (String format, Object ... args)
Vous permet d'imprimer un nombre arbitraire d'objets. Elle peut être appelée comme ceci:
System.out.printf ( "% s:% d,% s% n", nom, idnum, adresse);
Ou comme ceci
System.out.printf ( "% s:% d,% s,% s,% s% n", nom, idnum, adresse, téléphone, courriel);
Ou encore avec un nombre différent d'arguments.
Les Noms des Paramètres
Lorsque vous déclarez un paramètre d'une méthode ou d'un constructeur, vous donnez un nom à ce dernier. Ce nom est utilisé dans le corps de la méthode pour se référer à l'argument passé.
Le nom d'un paramètre doit être unique dans sa portée. Il ne peut pas avoir le même nom qu'un autre paramètre de la même méthode ou du même constructeur, et il ne peut pas avoir le même nom qu'une variable locale déclarée dans la méthode ou le constructeur.
Un paramètre peut avoir le même nom que l'un des champs de la classe. Si tel est le cas, le paramètre est dit qu'il shadow le champ. Shadowing champs peut rendre votre code difficile à lire et il est traditionnellement utilisé uniquement au sein des constructeurs et des méthodes qui définissent un champ particulier. Par exemple, considérez la classe Cercle et sa méthode setOrigin :
public class Cercle {
private int x, y, radius;
public void setOrigin(int x, int y) {
...
}
}
La classe Cercle a trois champs: x, y, et radius. La méthode SetOrigin? a deux paramètres, dont chacun a le même nom que l'un des champs. Chaque paramètre de la méthode shadow le champ qui partage son nom. Donc, l'utilisation des simples noms x ou y dans le corps de la méthode fait référence aux paramètres, et non pas aux champs. Pour accéder au champ, vous devez utiliser un nom qualifié. Cette question sera abordée plus loin dans cette leçon, dans la section intitulée "Utilisation du mot-clé '''this'''".
Passer des arguments à type de données primitifs
Les argument de types primitifs, comme un int ou un double, sont passés aux méthodes par ''valeur''. Cela signifie que toute modification apportée aux valeurs des paramètres n'existe que dans le cadre de la méthode. Quand la méthode se termine, les paramètres ne sont plus là et toutes les modifications sont perdues. Voici un exemple:
public class PassPrimitiveByValue {
public static void main(String[] args) {
int x = 3;
//invoke passMethod() with x as argument
passMethod(x);
// print x to see if its value has changed
System.out.println("After invoking passMethod, x = " + x);
}
// change parameter in passMethod()
public static void passMethod(int p) {
p = 10;
}
}
quand vous exécutez ce programme, l'affichage sera:
After invoking passMethod, x = 3
Passer des arguments de type de données références
Les paramètres de types de données référence , tels que les objets, sont également passés aux méthodes ''par valeur''. Cela signifie que lorsque la méthode se termine, la référence passée désigne toujours le même objet que précédemment. ''Cependant'', les valeurs des champs de l'objet ''peuvent'' être modifiées dans la méthode, s'ils ont le niveau d'accès.
Considérons, par exemple, une méthode d'une classe arbitraire qui déplace les objets de type Circle :
public void moveCircle(Circle circle, int deltaX, int deltaY) {
// code to move origin of circle to x+deltaX, y+deltaY
circle.setX(circle.getX() + deltaX);
circle.setY(circle.getY() + deltaY);
//code to assign a new reference to circle
circle = new Circle(0, 0);
}
Laissez la méthode être invoquée avec ces arguments:
MoveCircle? (myCircle, 23, 56)
Al'intérieur de la méthode, circle référence initialement myCircle. La méthode change les coordonnées x et y de l'objet que circle
référence (c'est-à-dire, myCircle) par 23 et 56, respectivement. Ces changements vont persister lorsque la méthode se termine. Puis circle lui est
attribuée une référence à un nouvel objet Circle avec x = y = 0. Cette réaffectation n'est pas définitive, cependant, parce que la
référence a été passée par valeur, et ne peut pas être modifiée. A l'interieur de la méthode, l'objet pointé par circle a changé, mais, quand la
méthode retourne, myCircle désignera toujours le même objet Circle comme avant que la méthode ne soit appelée.
Les Objets
Un programme Java typique crée de nombreux objets qui, comme vous le savez, interagissent en invoquant les méthodes ''Grâce'' à ces interactions entre objets, un programme peut effectuer diverses tâches, telles que la création d'une interface graphique, le lancement d'une animation, ou envoyer et recevoir des informations à travers un réseau. Une fois que l'objet a terminé le travail pour lequel il a été créé, ses ressources sont recyclés pour être utilisées par d'autres objets.
Voici un petit programme, appelé [CreateObjectDemo], qui crée trois objets: un objet [Point] et deux objets [Rectangle] . Vous aurez besoin de ces trois fichiers source pour compiler ce programme.
public class CreateObjectDemo {
public static void main(String[] args) {
//Declare and create a point object
//and two rectangle objects.
Point originOne = new Point(23, 94);
Rectangle rectOne = new Rectangle(originOne, 100, 200);
Rectangle rectTwo = new Rectangle(50, 100);
//display rectOne's width, height, and area
System.out.println("Width of rectOne: " + rectOne.width);
System.out.println("Height of rectOne: " + rectOne.height);
System.out.println("Area of rectOne: " + rectOne.getArea());
//set rectTwo's position
rectTwo.origin = originOne;
//display rectTwo's position
System.out.println("X Position of rectTwo: " + rectTwo.origin.x);
System.out.println("Y Position of rectTwo: " + rectTwo.origin.y);
//move rectTwo and display its new position rectTwo.move(40, 72);
System.out.println("X Position of rectTwo: " + rectTwo.origin.x);
System.out.println("Y Position of rectTwo: " + rectTwo.origin.y);
}
}
Ce programme crée, manipule, et affiche des informations sur les différents objets. Voici le résultat:
Width of rectOne: 100
Height of rectOne: 200
Area of rectOne: 20000
X Position of rectTwo: 23
Y Position of rectTwo: 94
X Position of rectTwo: 40
Y Position of rectTwo: 72
Les trois sections suivantes utilisent l'exemple ci-dessus pour décrire le cycle de vie d'un objet à l'intérieur d'un programme. De cela, vous apprendrez comment écrire un code qui crée et utilise des objets dans vos propres programmes. Vous apprendrez également comment le système nettoie un objet lorsque sa vie est terminée.
Créer des Objets
Comme vous le savez, une classe fournit le modèle pour les objets; vous créez un objet à partir d'une classe. Chacune des instructions suivantes tirées du programme [CreateObjectDemo] crée un objet et l'affecte à une variable:
Point originOne = new Point(23, 94);
Rectangle rectOne = new Rectangle(originOne, 100, 200);
Rectangle rectTwo = new Rectangle(50, 100);
La première ligne crée un objet de la classe [Point], la deuxième et troisième ligne, chacune d'elles crée un objet de la classe [Rectangle].
Chacune de ces instructions a trois parties (examinée en détail ci-dessous):
# '''Déclaration:''' Le code mis en '''gras''' sont toutes les déclarations de variables qui associent un nom de variable à un type d'objet.
# '''Instanciation:''' Le mot-clé '''new''' est un opérateur Java qui crée l'objet.
# '''Initialisation:''' L'opérateur new est suivi d'un appel à un constructeur, qui initialise le nouvel objet.
Déclarer une variable référençant un objet
Auparavant, vous avez appris que pour déclarer une variable, vous écrivez:
''type nom;''
Ceci informe le compilateur que vous utiliserez ''nom'' afin de référencer la donnée dont le type est ''type''. Avec une variable primitive, cette déclaration réserve également la bonne quantité de mémoire pour la variable.
Vous pouvez aussi déclarer une variable de référence sur sa propre ligne. Par exemple:
OriginOne? point;
Si vous déclarez originOne comme cela, sa valeur sera indéterminée jusqu'à ce que l'objet soit réellement créé et assigné à la variable. Déclarer uniquement une variable de référence ne crée pas un objet. Pour cela, vous devez utiliser l'opérateur '''new''', comme décrit dans la section suivante. Vous devez affecter un objet à originOne avant de l'utiliser dans votre code. Sinon, vous obtiendrez une erreur de compilation.
Une variable dans cet état, qui ne référence actuellement aucun objet, peut être illustré comme suit (le nom de la variable, originOne, plus une référence pointant vers rien):
Image:objet_null.gif|objet null?
Instancier une Classe
L'opérateur '''new''' instancie une classe en allouant de la mémoire pour un nouvel objet et en retournant une référence à cette mémoire. L'opérateur new invoque également le constructeur de l'objet.
'''Note:''' L'expression "instantiation d'une classe", signifie la même chose que "la création d'un objet." Lorsque vous créez un objet, vous créez une «''instance''» d'une classe, et donc vous "instanciez" une classe.
L'opérateur new a besoin d'un seul, postfix argument: un appel à un constructeur. Le nom du constructeur fournit le nom de la classe à instancier.
L'opérateur new renvoie une référence vers l'objet qu'il a crée. Cette référence est généralement affectée à une variable du type approprié, come:
Point originOne = new Point (23, 94);
La référence renvoyée par l'opérateur new n'a pas forcément besoin d'être affectée à une variable. Elle peut aussi être utilisée directement dans une expression. Par exemple:
Int height = new Rectangle (). Hauteur;
Cette instruction sera examinée dans la section suivante.
Initialiser un Objet
Voici le code de la classe Point:
public class Point {
public int x = 0;
public int y = 0;
//constructor
public Point(int a, int b) {
x = a;
y = b;
}
}
Cette classe contient un seul constructeur. Vous pouvez reconnaître facilement un
constructeur parceque sa déclaration utilise le même nom que la
classe et il n'a pas de type de retour. Le constructeur de la classe
Point prend deux arguments entiers, comme déclarée par le
code (int a, int b). L'instruction suivante donne 23 et 94 comme
valeurs pour ces arguments:
Point originOne = new Point (23, 94);
Le résultat de l'exécution de cette instruction peut être illustrée dans la figure suivante:
Image:objects-oneRef.gif?
Voici le code de la classe Rectangle, qui contient quatre constructeurs:
public class Rectangle {
public int width = 0;
public int height = 0;
public Point origin;
// four constructors
public Rectangle() {
origin = new Point(0, 0);
}
public Rectangle(Point p) {
origin = p;
}
public Rectangle(int w, int h) {
origin = new Point(0, 0);
width = w;
height = h;
}
public Rectangle(Point p, int w, int h) {
origin = p;
width = w;
height = h;
}
// a method for moving the rectangle
public void move(int x, int y) {
origin.x = x;
origin.y = y;
}
// a method for computing the area of the rectangle
public int getArea() {
return width * height;
}
}
Chaque constructeur vous permet de fournir des valeurs initiales pour
la taille et la largeur du rectangle, en utilisant à la fois des types
primitifs et références . Si une classe possède plusieurs
constructeurs, ils doivent avoir des signatures différentes. Le
compilateur Java différencie les constructeurs en se basant sur le nombre et
le type des arguments. Lorsque le compilateur Java rencontre le code
suivant, il saura appeler le constructeur de la classe rectangle qui a
besoin d'un argument de type Point suivi par deux arguments de type entier:
Rectangle rectOne = new Rectangle (originOne, 100, 200);
Ceci appelle un des constructeurs de Rectangle qui initialise origin à originOne. Aussi, le constructeur définit la largeur à 100 et la hauteur
à 200. Maintenant, il y a deux références au même objet Point (un
objet peut avoir plusieurs références vers celui-ci, comme indiqué dans la figure suivante) :
Image:objects-oneRef.gif?
La ligne de code suivante appelle le constructeur de Rectangle qui
requiert deux arguments entiers, lesquels fournissent les valeurs initiales
pour la largeur et la hauteur. Si vous inspecter le code du
constructeur, vous verrez que celui ci crée un nouvel objet Point dont ses
valeurs x et y sont initialisées à 0:
Rectangle rectTwo = new Rectangle (50, 100);
Le constructeur de Rectangle utilisé dans la déclaration suivante ne prend
aucun paramètre, du coup il est appelé un constructeur sans arguments:
Rectangle rect = new Rectangle ();
Toutes les classes ont au moins un constructeur. Si une classe n'en déclare pas un
explicitement, le compilateur Java lui fournit
automatiquement un constructeur sans arguments, appelé ''le constructeur par
défaut''. Ce constructeur par défaut appelle le constructeur sans arguments de la classe parente
, ou le constructeur de la classe Object si la classe n'a pas d'autre
parent. Si le parent n'a pas de constructeur (Object doit en avoir un), le
compilateur rejettera le programme.
Utiliser des Objets
Une fois que vous avez créé un objet, vous voulez probablement l'utiliser pour quelque chose. Vous aurez peut-être besoin d'utiliser la valeur de l'un de ses champs, changer l'un de ses champs, ou appeler l'une de ses méthodes pour effectuer une action.
Référencer les Champs d'un Objet
Les champs d'un objet sont accessibles par leur nom. Vous devez utiliser un nom qui n'est pas ambigüe.
Vous pouvez utiliser un simple nom pour un champ à l'intérieur de sa classe. Par exemple, nous pouvons ajouter une instruction ''au sein'' de la classe Rectangle qui affiche la largeur et la hauteur:
System.out.println ( "largeur et la hauteur sont:" width "," height);
Dans ce cas, la largeur et la hauteur sont de simples noms.
Un code qui est en dehors de la classe de l'objet doit utiliser une référence vers l'objet ou une expression, suivi par l'opérateur ''point'' (.) , suivi à son tour d'un simple nom du champ, comme dans ce qui suit:
ObjectReference?.fieldName
Par exemple, le code dans la classe CreateObjectDemo? est en dehors du code de la classe Rectangle. Donc,pour référencer les champs origine, la largeur et la hauteur de l'objet de type Rectangle nommé rectOne, la classe CreateObjectDemo? doit utiliser les noms rectOne.origin, rectOne.width et rectOne.height, respectivement. Le programme utilise deux de ces noms pour afficher la largeur et la hauteur de rectOne:
System.out.println ( "Largeur de rectOne:" rectOne.width);
System.out.println ( "Hauteur de la rectOne:" rectOne.height);
Tenter d'utiliser les simples noms width et height dans le code de la classe CreateObjectDemo? n'a pas de sens - ces champs existent seulement à l'intérieur d'un objet - et se traduit par une erreur de compilation.
Plus tard, le programme utilisera le même code pour afficher des informations sur rectTwo. Les objets de même type ont leur propre copie des mêmes instances des champs. Ainsi, chaque objet Rectangle possède des champs nommés origine, width et height . Lorsque vous accédez à une instance d'un champ à travers une référence vers un objet, vous référencez ce champ particulier de l'objet. Les deux objets rectOne et rectTwo dans le programme CreateObjectDemo? ont differents champs origin,width et height.
Pour accéder à un champs, vous pouvez utiliser une référence nommée vers un objet, comme dans les exemples précédents, ou vous pouvez utiliser n'importe quelle expression qui renvoie une réference vers un objet. Rappelons que l'opérateur ''new'' renvoie une référence vers un objet. Donc, vous pourriez utiliser la valeur retournée par new pour accéder au champ du nouvel objet :
Int height = new Rectangle (). Hauteur;
Cette instruction crée un nouvel objet Rectangle et obtient aussitôt sa hauteur. En substance, l'instruction calcule la hauteur par défaut d'un Rectangle. Notez qu'après que cette instruction est exécutée, le programme n'a plus de référence vers le Rectangle qui vient d'être créé, car le programme n'a jamais stocké la référence nulle part. L'objet est non référencé, et ses ressources sont libres d'être recyclées par la machine virtuelle Java.
Appeler les Méthodes d'un Objet
Vous pouvez également utiliser une référence à un objet afin d'invoquer les méthodes de l'objet. Vous ajoutez simplement le nom de la méthode à la référence de l'objet, avec l'intervention de l'opérateur ''point'' (.). Aussi, vous pouvez fournir les arguments de la méthode entre les parenthèses. Si la méthode ne nécessite aucun argument, utiliser des parenthèses vides.
ObjectReference?.methodName (argumentList);
Ou
ObjectReference?.methodName ();
La classe Rectangle dispose de deux méthodes: getArea () pour calculer la superficie du rectangle et move() pour changer l'origine du rectangle. Voici le code de CreateObjectDemo? qui invoque ces deux méthodes:
System.out.println ( "Domaine de rectOne:" rectOne.getArea ());
...
RectTwo.move (40, 72);
La première instruction invoque la méthode getArea() de l'objet rectOne et affiche les résultats. La deuxième ligne déplace rectTwo parce que la méthode move() affecte de nouvelles valeurs à origin.x et origin.y.
Comme dans le cas des champs, ''objectReference'' doit être une référence vers un objet. Vous pouvez utiliser un nom de variable, mais vous pouvez également utiliser n'importe quelle expression qui renvoie une référence à un objet. L'opérateur new renvoie une référence d'objet, de sorte que vous pouvez utiliser la valeur retournée par new afin d'invoquer la méthode du nouvel objet:
Nouveau Rectangle (100, 50). GetArea ();
L'expression "new Rectangle (100, 50)" retourne une référence qui désigne un objet Rectangle. Comme indiqué, vous pouvez utiliser la notation du point(.) pour invoquer la méthode getArea() de "new Rectangle" afin de calculer la surface du nouveau rectangle.
Certaines méthodes, comme getArea(), retournent une valeur. Pour les méthodes qui renvoient une valeur, vous pouvez utiliser la méthode d'invocation dans les expressions. Vous pouvez affecter la valeur de retour à une variable, l'utiliser pour prendre des décisions, ou contrôler une boucle. Ce code affecte la valeur retournée par getArea() à la variable areaOfRectangle:
Int areaOfRectangle = new Rectangle (100, 50). GetArea ();
Rappelez-vous, l'invocation d'une méthode sur un objet particulier revient au même que l'envoi d'un message à cet objet. Dans ce cas, l'objet auquel getArea() est invoquée est le rectangle renvoyé par le constructeur.
Le Garbage Collector
Certains langages orientés objets requièrent de garder une trace de tous les objets que vous créez et que vous les détruisez dés que vous n'en aurez plus besoin. Gérer la mémoire soi même est fastidieux et source d'erreurs. La plate-forme Java vous permet de créer autant d'objets que vous voulez (dans la limite, bien entendu, de ce que votre système peut manipuler), et vous n'avez pas à vous soucier de leur destruction. L'environnement d'exécution de Java supprime les objets quand il détermine qu'ils ne sont plus utilisés. Ce processus est appelé ''Garbage Collection''.
Un objet est éligible à la collecte et la suppression (Garbage Collection) quand il n'y a plus de références à cet objet. Les références qui sont détenus dans une variable sont généralement abandonnées lorsque la variable est hors de portée. Ou bien, vous pouvez explicitement supprimer une référence vers un objet en définissant la variable à la valeur spéciale '''null'''. Rappelez-vous qu'un programme peut avoir plusieurs références sur le même objet, toutes les références à un objet doivent être supprimées avant que l'objet ne soit éligible à la suppression définitive de la mémoire.
L'environnement d'exécution Java a un Ramasse-Miettes ('''Garbage Collector''') qui libère périodiquement la mémoire utilisée par les objets qui ne sont plus référencés. Le ramasse-miettes fait automatiquement son travail lorsqu'il détermine que le bon moment est venu.
En savoir plus sur les Classes
Cette section traite de plusieurs aspects de classes qui dépendent de l'utilisation de références d'objets et de l'opérateur ''point'' que vous avez appris dans les sections précédentes sur les objets:
* Les valeurs de retour des méthodes.
* Le mot clé this.
* Classe vs instance des membres.
* Contrôle d'accès.
Retourner une valeur à partir d'une méthode
Une méthode retourne au code qui l'a appelé quand elle :
* termine toutes les instructions contenues dans la méthode,
* atteint une instruction de retour, ou
* lance une exception (décrite plus loin),
Selon la première éventualité.
Vous spécifiez le type de retour de la méthode dans sa déclaration. A l'intérieur de la méthode, vous utilisez l'instruction de retour pour renvoyer la valeur.
Toute méthode qui utilise la déclaration ''void'' ne retourne pas de valeur. Elle n'a pas besoin de contenir une instruction de retour, mais elle peut le faire. Dans ce cas, une instruction de retour peut être utilisée pour se détacher d'un bloc du flux contrôle et sortir de la méthode, et elle peut être simplement utilisée comme ceci:
return;
Si vous tentez de retourner une valeur à partir d'une méthode qui est déclarée ''void'', vous obtiendrez une erreur de compilation.
Toute méthode qui n'est pas déclarée ''void'' doit contenir une instruction de retour avec la valeur de retour correspondante, comme ceci:
return returnValue;
Le type de données de la valeur de retour doit correspondre au type de retour figurant dans la déclaration de la métohde , on ne peut pas retourner une valeur "entier" à partir d'une méthode déclarée pour renvoyer un "booléen".
La méthode getArea() dans la classe [Rectangle] qui a été étudiée dans les sections sur les objets retourne un entier:
// a method for computing the area of the rectangle
public int getArea() {
return width * height;
}
Cette méthode renvoie un entier que l'expression largeur * hauteur a évalué.
La méthode renvoie un type primitif. Une méthode peut également renvoyer un type référence. Par exemple, dans un programme de manipulation des objets Bicycle, nous pourrions disposer d'une méthode comme ceci:
public Bicycle seeWhosFastest(Bicycle myBike, Bicycle yourBike, Environment env) {
Bicycle fastest;
// code to calculate which bike is faster, given
// each bike's gear and cadence and given
// the environment (terrain and wind)
return fastest;
}
Retourner une Classe ou une Interface
Si cette section vous embrouille, sautez là et revenez à elle après que vous ayez terminé la leçon sur les interfaces et l'héritage.
Quand une méthode utilise un nom de classe comme type de retour, comme whosFastest l'a fait, la classe du type de l'objet renvoyé doit être soit une sous-classe, soit la classe exacte du type de retour. Supposons que vous avez une hiérarchie de classe dans laquelle ImaginaryNumber? est une sous-classe de java.lang.Number, qui est à son tour une sous-classe de classe Object, comme illustré dans la figure suivante:
Image:classes-hierarchy.gif?
'''''La hiérarchie de classe de ImaginaryNumber?'''''
Maintenant, supposez que vous avez une méthode déclarée pour retourner un Number:
public Number returnANumber() {
...
}
La méthode ''returnANumber()'' peut renvoyer aussi un ''ImaginaryNumber'' mais pas un ''Object''. ''ImaginaryNumber''
est un Number parceque c'est une sous classe de ''Number''. Cependant, un ''Object'' n'est pas nécessairement un ''Number'' (il peut être un String ou un autre type)
Vous pouvez surcharger une méthode et la définir de telle sorte qu'elle retourne une sous-classe de la méthode originale, comme ceci:
public ImaginaryNumber returnANumber() {
...
}
Cette technique, appelée ''covariance du type de retour'', signifie que le type de retour est autorisé à varier dans le même sens que la sous-classe.
'''Note:''' Vous pouvez aussi utiliser les noms d'interface comme types de retour. Dans ce cas, l'objet retourné doit implémenter l'interface spécifiée.
Utiliser le mot clé "this"
Dans le cadre d'une méthode d'instance ou d'un constructeur, '''this''' fait référence à ''l'objet courant'' - l'objet dont la méthode ou le constructeur est appelé. Vous pouvez vous référer à tout membre de l'objet courant à partir d'une méthode d'instance ou d'un constructeur à l'aide du mot clé '''this'''.
Utiliser "this" avec un Champ
La raison la plus courante qui justifie l'utilisation du mot-clé '''this''' est le fait qu'un champ est caché par un paramètre d'une méthode ou d'un constructeur.
Par exemple, la classe Point a été écrit comme ceci:
public class Point {
public int x = 0;
public int y = 0;
//constructor
public Point(int a, int b) {
x = a;
y = b;
}
}
mais elle aurait pu être écrite comme ceci aussi:
public class Point {
public int x = 0;
public int y = 0;
//constructor
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
Chaque argument du deuxième constructeur cache l'un des champs de
l'objet (à l'intérieur du constructeur,x est une copie locale du premier argument).Pour désigner le champ x dela classe Point , le
constructeur doit utiliser '''this.x'''.
Utiliser "this" avec un Constructeur
À l'intérieur d'un constructeur, vous pouvez également utiliser le mot-clé '''this''' pour appeler un autre
constructeur de la même classe. C'est ce qu'on appelle ''une invocation explicite d'un constructeur''.
Voici une autre classe Rectangle, avec une implémentation différente de celle se trouvant dans la
section [Objets].
public class Rectangle {
private int x, y;
private int width, height;
public Rectangle() {
this(0, 0, 0, 0);
}
public Rectangle(int width, int height) {
this(0, 0, width, height);
}
public Rectangle(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
...
}
Cette classe contient un ensemble de constructeurs. Chaque constructeur
initialise une partie ou la totalité des variables membres (ou champs) de la classe Rectangle .
Les constructeurs fournissent une valeur par défaut pour toute variable membre dont la valeur initiale
n'est pas fournie par un argument.
Par exemple, le constructeur sans arguments appelle le constructeur à quatre-arguments
avec quatre valeurs 0 et le constructeur à deux-argument
appelle le constructeur à quatre-arguments avec deux valeurs 0. Comme
précédemment, le compilateur détermine quel constructeur appeler, en fonction du nombre et du type d'arguments.
S'il est présent, l'invocation d'un autre constructeur doit se trouver à la première ligne du constructeur.
Contrôler l'Accès aux Membres d'une Classe
Les modificateurs du niveau d'accès déterminent si d'autres classes peuvent utiliser un champ particulier ou invoquer une méthode particulière. Il existe deux niveaux de contrôle d'accès:
* Au niveau supérieur: public ou package-private (pas de modificateur explicite).
* Au niveau des membres: public, private, protected, ou package-private (pas de modificateur explicite).
Une classe peut être déclarée avec le modificateur public, dans ce cas, cette classe est visible à toutes les classes partout ailleurs. Si une classe n'a aucun modificateur (la valeur par défaut, aussi connu sous le nom de package-private), elle est visible seulement au sein de son propre package(un package se définit comme un groupes de classes- vous en apprendrez plus sur eux dans une leçon ultérieure.)
Au niveau des membres, vous pouvez aussi utiliser le modificateur public ou pas de modificateur (package-private) tout comme avec les classes de premier niveau, et avec la même signification. Pour les membres, il y a deux autres modificateurs d'accès: private et protected. Le modificateur private précise que le membre ne peut être accédé qu'à partir de sa propre classe. Le modificateur protected spécifie que le membre ne peut être accédé qu'à partir de son propre package(comme avec les package-private) et, en outre, à partir d'une sous-classe de sa classe dans un autre package.
Le tableau suivant montre l'accès aux membres autorisé par chaque modificateur:
{| border=1
|+ Les niveaux d'accès
! Modificateur!! Classe!! Package!! Sous-Classe!! Partout
|-
| public || Oui || Oui || Oui || Oui
|-
| protected || Oui || Oui || Oui || Non
|-
| ''aucun modificateur''|| Oui || Oui || Non || Non
|-
| private || Oui || Non || Non || Non
|}
La première colonne indique si la classe elle-même a accès au membre défini par le niveau d'accès. Comme vous pouvez le voir, une classe a toujours accès à ses propres membres. La seconde colonne indique si les classes du même package que la classe (indépendamment de leur lien d'héritage) ont accès au membre. La troisième colonne indique si les sous-classes de la classe - déclaré en dehors de ce package- ont accès au membre. La quatrième colonne indique si toutes les classes ont accès au membre.
Les niveaux d'accès vous affectent de deux façons. Tout d'abord, lorsque vous utilisez des classes qui proviennent d'une autre source (telles que les classes dans la plate-forme Java), les niveaux d'accès déterminent quels membres de ces classes, vos propres classes peuvent utiliser. Deuxièmement, quand vous écrivez une classe, vous devez décider quel niveau d'accès que chaque variable membre et chaque méthode dans votre classe devraient avoir.
Observons une collection de classes et voyons comment les niveaux d'accès affectent la visibilité. La figure suivante montre quatre classes dans cet exemple, et comment elles sont liées:
Image:Classes-access.gif?
'''''Les classes et les packages de l'exemple sont utilisés pour illustrer les niveaux d'accès'''''
Le tableau ci-dessous montre où les membres de la classe Alpha sont visibles pour chacun des accès de modificateurs qui peuvent s'appliquer à eux:
{| border=1
|+ Visibilité
! Modificateur!! Alpha!! Beta!! Sous-Alpha!! Gamma
|-
| public || Oui || Oui || Oui || Oui
|-
| protected || Oui || Oui || Oui || Non
|-
| ''aucun modificateur''|| Oui || Oui || Non || Non
|-
| private || Oui || Non || Non || Non
|}
'''Conseils sur le choix d'un niveau d'accès:''' Si d'autres programmeurs utiliseront votre classe, vous voulez vous assurer que les erreurs d'une mauvaise utilisation ne peuvent pas se produire. Les niveaux d'accès peuvent vous aider à faire cela.
* Utiliser le niveau d'accès le plus restrictif, qui a un sens pour un membre particulier. Utilisez private sauf si vous avez une bonne raison de ne pas le faire.
* Évitez les champs publiques, sauf pour les constantes. (Bon nombre d'exemples dans le tutoriel utilisent des champs publiques. Cela peut aider à illustrer certains points de manière concise, mais n'est pas recommandé pour la production de code) Les champs publiques ont tendance à vous lier à une implémentation particulière et ainsi limiter votre flexibilité dans la modification de votre code.
Comprendre les Membres d'Instance et de Classe
Dans cette section, nous discutons de l'utilisation du mot clé '''static''' pour créer des champs et des méthodes qui appartiennent à la classe, plutôt que qu'à l'instance de la classe.
Les Variables de Classe
Quand un certain nombre d'objets sont créés à partir du même modèle de classe, ils ont chacun leurs propres copies des ''variables d'instance''. Dans le cas de la classe Bicycle, les variables d'instance sont cadence, gear, et speed. Chaque objet Bicycle a ses propres valeurs pour ces variables, stockées dans différents emplacements de la mémoire.
Parfois, vous voulez avoir des variables qui sont communes à tous les objets. Cette opération peut être réalisée grâce au modificateur statique . Les champs qui ont le modificateur statique dans leur déclaration sont appelées ''champs statiques'' ou ''variables de classe''. Ils sont associés à la classe, au lieu des objets. Chaque instance de la classe partage une variable de classe, lequel est dans un emplacement fixe de la mémoire. Tout objet peut changer la valeur d'une variable de classe, mais les variables de classe peuvent aussi être manipulées sans créer une instance de classe.
Par exemple, supposons que vous voulez créer un certain nombre d'objets de Bicycle et leur assigner chacun un numéro de série, en commençant par 1 pour le premier objet. Ce numéro d'identification est unique à chaque objet et est donc une variable d'instance. Mais en même temps, vous avez besoin d'un champ pour garder une trace du nombre d'objets Bicycle qui ont été créés afin de savoir quel ID attribuer au prochain objet créé. Ce champ n'est liée à aucun objet individuellement, mais à la classe dans son ensemble. Pour cela, vous avez besoin d'une variable de classe, numberOfBicycles, comme suit:
public class Bicycle{
private int cadence;
private int gear;
private int speed;
// add an instance variable for the object ID
private int id;
// add a class variable for the number of Bicycle objects instantiated
private static int numberOfBicycles = 0;
......
}
Les variables de classe sont référencées par le nom de la classe elle-même, comme dans
Bicycle.numberOfBicycles
Cela montre clairement qu'ils sont des variables de classe.
'''Note:''' On peut aussi référencer les champs statiques avec une référence d'objet comme ceci
MyBike.numberOfBicycles
Mais cette méthode est déconseillée car elle ne précise pas clairement qu'ils sont des variables de classe.
Vous pouvez utiliser le constructeur de Bicycle pour fixer la variable d'instance ''id'' et incrémenter la variable de classe numberOfBicycles :
public class Bicycle{
private int cadence;
private int gear;
private int speed;
private int id;
private static int numberOfBicycles = 0;
public Bicycle(int startCadence, int startSpeed, int startGear){
gear = startGear;
cadence = startCadence;
speed = startSpeed;
// increment number of Bicycles and assign ID number
id = ++numberOfBicycles;
}
// new method to return the ID instance variable
public int getID() {
return id;
}
.....
}
Les Méthodes de Classe
Le langage de programmation Java supporte aussi bien les méthodes statiques que des variables statiques. Les méthodes statiques, qui ont les modificateurs statiques dans leur déclaration, devraient être invoquées par le nom de classe, sans avoir à créer une instance de la classe, comme dans
ClassName.methodName(args)
'''Note:''' On peut aussi utiliser les méthode statiques avec une référence d'objet comme ceci
InstanceName.methodName (args)
Mais cette méthode est déconseillée car elle ne précise pas clairement qu'elles sont des méthodes de classe.
Une utilisation fréquente des méthodes statiques consiste permettre l'accès aux champs statiques. Par exemple, nous pourrions ajouter une méthode statique à la classe Bicycle pour accéder au champ statique numberOfBicycles :
public static int getNumberOfBicycles() {
return numberOfBicycles;
}
Pas toutes les combinaisons de variables et d'instances de classes et méthodes sont autorisées:
* Les méthodes d'instance peuvent par exemple accéder à des variables et des méthodes d'instance directement.
* Les méthodes d'instance peuvent accéder aux variables et méthodes de classe directement.
* Les méthodes de classe peuvent accéder aux variables et méthodes de classe directement.
* Les méthodes de classe '''''ne peuvent pas''''' accéder aux variables ou méthodes d'instance directement - elles doivent passer par une référence d'objet. Aussi, les méthodes de classe ne peuvent pas utiliser le mot clé '''this''' parce qu'il n'y a aucune instance pour cette référence.
Les Constantes
Le modificateur '''static''', en combinaison avec le modificateur '''final''', est également utilisée pour définir des ''constantes''. Le modificateur final indique que la valeur de ce champ ne peut pas changer.
Par exemple, la déclaration suivant d'une variable définit une constante appelée PI, dont la valeur est une approximation de pi (le rapport de la circonférence d'un cercle à son diamètre):
Static final double PI = 3,141592653589793;
Des constantes définies de cette manière ne peuvent pas être réaffectées, et il générera une erreur de compilation si votre programme essaie de le faire. Par convention, le nom des valeurs constantes sont définies en majuscules. Si le nom est composé de plus d'un mot, les mots sont séparés par un caractère de soulignement (_).
'''Note:''' Si un type primitif ou une chaîne est définie comme une constante, et que la valeur est connue au moment de la compilation, le compilateur remplace le nom de la constante partout dans le code avec sa valeur. C'est ce qu'on appelle ''compile-time constant''. Si la valeur de la constante dans le monde externe change (par exemple, si il est dit que pi devrait être maintenant 3,975), vous devrez recompiler toute classe qui utilise cette constante pour obtenir la valeur actuelle.
La Classe Bicycle
Après toutes les modifications apportées dans cette sestion, la classe Bicycle devient maintenant :
public class Bicycle{
private int cadence;
private int gear;
private int speed;
private int id;
private static int numberOfBicycles = 0;
public Bicycle(int startCadence, int startSpeed, int startGear){
gear = startGear;
cadence = startCadence;
speed = startSpeed;
id = ++numberOfBicycles;
}
public int getID() {
return id;
}
public static int getNumberOfBicycles() {
return numberOfBicycles;
}
public int getCadence(){
return cadence;
}
public void setCadence(int newValue){
cadence = newValue;
}
public int getGear(){
return gear;
}
public void setGear(int newValue){
gear = newValue;
}
public int getspeed(){
return speed;
}
public void applyBrake(int decrement){
speed -= decrement;
}
public void speedUp(int increment){
speed += increment;
}
}
Initialiser les Champs
Comme vous l'avez vu, vous pouvez souvent fournir une valeur initiale pour un champ lors de sa déclaration:
public class BedAndBreakfast? {
public static int capacity = 10; //initialize to 10
private boolean full = false; //initialize to false
}
Cela fonctionne bien quand la valeur d'initialisation est disponible et que
l'initialisation peut être rédigée sur une seule ligne. Toutefois, cette
forme d'initialisation a des limites en raison de sa simplicité. Si
l'initialisation requiert une certaine logique (par exemple, la gestion
des erreurs ou le besoin d'utiliser une boucle pour remplir une liste complexe), une
simple affectation est insuffisante. Les variables d'instance peuvent être
initialisées dans des constructeurs, lorsque la gestion des erreurs ou d'autres
logiques s'imposent. Pour fournir la même possibilité pour les variables de classe
, le langage de programmation Java propose des ''blocs d'initialisation statique''.
'''Note:''' Il n'est pas nécessaire de déclarer les champs au début de la définition de la classe, bien que
ce soit la pratique la plus courante. Il est seulement nécessaire qu'ils soient déclarés et initialisés avant qu'ils ne soient
utilisés.
Les Blocs d'Initialisation Statique
Un ''bloc d'initialisation statique'' est un bloc de code normal entouré d'accolades, { }, et précédé du mot clé '''static''' .
Voici un exemple:
static {
// whatever code is needed for initialization goes here
}
Une classe peut avoir n'importe quel nombre de blocs d'initialisation statique, et ils peuvent apparaître n'importe où dans le corps de classe. Le système d'exécution garantit que les blocs d'initialisation statique sont appelés dans l'ordre où ils apparaissent dans le code source.
Il existe une alternative aux blocs-statique, vous pouvez écrire une méthode statique privée:
class Whatever {
public static varType myVar = initializeClassVariable();
private static varType initializeClassVariable() {
//initialization code goes here
}
}
L'avantage d'une méthode statique et privée, est qu'elle peut être utilisée plus tard si vous avez besoin de réinitialiser une variable de classe.
Initialiser les Membres d'Instance
Normalement, vous devriez mettre le code d'initialisation d'une
variable d'instance dans un constructeur. Il y a deux alternatives à
l'utilisation d'un constructeur pour initialiser des variables d'instance: les blocs d'initialisation et les méthodes finales.
Les blocs d'initialisation pour les variables d'instance ressemblent beaucoup aux blocs d'initialisation
statique, mais sans utiliser le mot clé '''static''':
{
// whatever code is needed for initialization goes here
}
Le compilateur Java copie les blocs d'initialisation dans chaque constructeur. Par conséquent, cette approche peut être utilisée pour
partager un bloc de code entre plusieurs constructeurs.
Une ''méthode finale'' ne peut pas être surchargée dans une sous-classe.
Cette question sera abordée dans le cours sur les interfaces et l'héritage.
Voici un exemple de l'utilisation d'une méthode finale pour initialiser une variable d'instance:
class Whatever {
private varType myVar = initializeInstanceVariable();
protected final varType initializeInstanceVariable() {
//initialization code goes here
}
}
Ceci est particulièrement utile si les sous-classes voudraient réutiliser cette méthode d'initialisation. La méthode d'appel est ''finale'' , car appeler des méthodes non finales durant l'initialisation peut causer des problèmes. Joshua Bloch décrit plus en détail dans Effective Java.
Résumé sur la création et l'utilisation des classes et des objets
Une déclaration de classe donne un nom à la classe et entoure le corps entre accolades. Le nom de classe peut être précédé de modificateurs. Le corps de classe contient des champs, des méthodes et des constructeurs pour la classe. Une classe utilise des champs pour contenir les informations d'état et utilise des méthodes pour implémenter le comportement. Les constructeurs qui initialisent une nouvelle instance d'une classe utilisent le nom de la classe et ressemblent à des méthodes sans type de retour.
Vous contrôlez l'accès aux classes et aux membres de la même manière: en utilisant un modificateur d'accès tel que ''public'' dans leur déclaration.
Vous spécifiez une variable de classe ou une méthode de classe en utilisant le mot-clé ''static'' dans la déclaration du membre. Un membre qui n'est pas déclarée comme statique est implicitement un membre d'instance . Les variables de classe sont partagées par toutes les instances d'une classe et peuvent être accèdées via le nom de la classe ainsi que via une référence d'instance . Les instances d'une classe obtiennent leur propre copie de chaque variable d'instance, qui doit être accédée via une référence d'instance.
Vous créez un objet d'une classe à l'aide l'opérateur ''new'' et du constructeur. L'opérateur new renvoie une référence à l'objet qui a vient d'être créé. Vous pouvez affecter la référence à une variable ou l'utiliser directement.
Les variables d'instance et les méthodes qui sont accessibles par le code à l'extérieur de la classe où ils ont été déclarés , peuvent être référencés à l'aide d'un nom qualifié. Un nom qualifié d'une variable d'instance ressemble à ceci:
objectReference.variableName
Un nom qualifié d'une métohde ressemble à ceci:
objectReference.methodName(argumentList)
ou
objectReference.methodName()
Le ramasse miettes (Garbage Collector) nettoie automatiquement les objets inutilisés. Un objet est inutilisé si le programme n'a plus de références vers lui. Vous pouvez supprimer automatiquement la référence en affectant ''null'' à la variable qui contient la référence .
Les Classes Imbriquées
Le langage de programmation Java vous permet de définir une classe à l'intérieur d'une autre classe. Une telle classe est appelée une classe imbriquée et est illustrée ici:
class OuterClass? {
...
class NestedClass? {
...
}
}
'''Terminologie:''' Les Classes Imbriquées sont divisées en deux catégories:
statiques et non statiques. Les classes imbriquées qui sont déclarées statiques
sont simplement appelées classes imbriquées statiques. Les non statiques
sont appelées ''les classes internes''.
class OuterClass? {
...
static class StaticNestedClass? {
...
}
class InnerClass? {
...
}
}
Une classe imbriquée est membre de sa classe englobante. Les classes imbriquées non-statiques (les classes internes ) ont accès aux autres membres de la classe englobante, même si elles sont déclarées private. Les classes imbriquées statiques, par contre, n'ont pas accès aux autres membres de la classe englobante. Comme un membre d'une classe externe, une classe imbriquée peut être déclarée private, public, protected ou package private. (Rappelons que les classes externes ne peuvent être déclarés que public ou package private).
Pourquoi Utiliser Les Classes Imbriquées ?
Il y a plusieurs raisons pour lesquelles vous utilisez les classes imbriquées, parmi lesquelles:
* C'est une façon logique de regrouper des classes qui ne sont utilisées que dans un seul endroit.
* Il accroît l'encapsulation.
* Les classes imbriquées peuvent conduire à un code plus lisible et plus maintenable .
'''Regroupement logique de classes''' : Si une classe est utile à seulement une seule autre classe, alors il est logique de l'intégrer dans cette classe et garder les deux ensemble. Nesting such "helper classes" makes their package more streamlined.
'''Augmentation de l'encapsulation''' : Considérons deux classes de premier niveau, A et B, où B doit avoir accès à des membres de A qui, sinon, seraient déclarées privées. En cachant la classe B à l'intérieur de la classe A, les membres de A peuvent être déclarés private et B peut leur accéder. En outre, B elle-même peut être cachée du monde extérieur.
'''Code plus lisible, et plus maintenable''' : Imbrication de petites classes dans les classes de premier niveau de code place la plus proche où il est utilisé.
Les Classes Imbriquées Statiques
Comme avec les méthodes et les variables de classe, une classe imbriquée statique est associée à sa classe externe . Et comme les méthodes de classe statiques , une classe imbriquée statique ne peut pas référencer directement les variables ou méthodes d'instance définies dans sa classe englobante (elle ne peut les utiliser qu'à travers une référence d'objet) .
'''Note:''' Une classe imbriquée statique interagit avec les membres d'instance de sa classe externe (et d'autres classes), comme n'importe quelle autre classe de plus haut niveau. En effet, une classe imbriquée statique est behaviorally de haut niveau qui a été imbriquée dans une autre classe de haut niveau pour packaging convenience.
Les classes imbriquées statiques sont accessibles en utilisant le nom de la classe englobante:
OuterClass.StaticNestedClass
Par exemple, pour créer un objet de la classe imbriquée statique , utilisez la syntaxe:
OuterClass.StaticNestedClass nestedObject = new StaticNestedClass? ();
Les Classes Internes
Comme avec des méthodes et des variables d'instance, une classe interne est associée à une instance de sa classe englobante et a directement accès aux méthodes et aux champs de cet objet . Aussi, parce qu'une classe interne est associée à une instance, elle ne peut pas définir elle-même des membres statiques.
Les objets qui sont des instances d'une classe interne existent ''au sein'' d'une instance de la classe externe. Considérez les classes suivantes:
class OuterClass? {
...
class InnerClass? {
...
}
}
Une instance de InnerClass? ne peut exister qu'au sein d'une instance de la classe
OuterClass? et a un accès direct aux méthodes et champs de l'objet englobant. La figure suivante illustre cette idée.
Image:Classes-inner.gif?
'''''Une classe interne existe au sein d'une instance de la classe englobante'''''
Pour instancier une classe interne, vous devez d'abord instancier la
classe externe. Ensuite, créez l'objet interne à l'intérieur de l'objet externe avec cette syntaxe:
OuterClass.InnerClass innerObject = outerObject.new InnerClass? ();
En outre, il existe deux types spéciaux de classes internes: les classes locales et les
classes anonymes (aussi appelées classes anonymes internes). Ces deux là,
seront discutées brièvement dans la section suivante.
Exemple de Classe Interne
Pour voir une classe interne en action, nous allons d'abord voir un tableau. Dans l'exemple suivant, nous allons créer un tableau, le remplir avec des valeurs entières, puis afficher seulement les valeurs des indices de ce même tableau par ordre croissant.
La classe DataStructure? qui est en dessous est composée de:
* La classe ''DataStructure'' externe, qui inclut des méthodes pour ajouter un entier dans le tableau et afficher les valeurs des indices de ce tableau.
* La classe interne ''InnerEvenIterator'' , qui est semblable à un ''itérateur'' Java standard (Iterator). Les itérateurs sont utilisés pour parcourir une structure de données et ont généralement des méthodes de test du dernier élément, de récupération de l'élément courant, et de passage à l'élément suivant.
* Une méthode principale qui instancie un objet DataStructure? (ds) et l'utilise pour remplir le tableau arrayOfInts avec des valeurs entières(0, 1, 2, 3, etc), ensuite appelle une méthode printEven afin d'afficher les valeurs des indices de arrayOfInts .
public class DataStructure? {
//create an array
private final static int SIZE = 15;
private int[] arrayOfInts = new int[SIZE];
public DataStructure?() {
//fill the array with ascending integer values
for (int i = 0; i < SIZE; i++) {
arrayOfInts[i] = i;
}
}
public void printEven() {
//print out values of even indices of the array
InnerEvenIterator? iterator = this.new InnerEvenIterator?();
while (iterator.hasNext()) {
System.out.println(iterator.getNext() + " ");
}
}
//inner class implements the Iterator pattern
private class InnerEvenIterator? {
//start stepping through the array from the beginning
private int next = 0;
public boolean hasNext() {
//check if a current element is the last in the array
return (next <= SIZE - 1);
}
public int getNext() {
//record a value of an even index of the array
int retValue = arrayOfInts[next];
//get the next even element
next += 2;
return retValue;
}
}
public static void main(String s[]) {
//fill the array with integer values and print out only values of even indices
DataStructure? ds = new DataStructure?();
ds.printEven();
}
}
La sortie est:
0 2 4 6 8 10 12 14
Notez que la classe InnerEvenIterator? référence directement la variable d'instance l'arrayOfInts de l'objet DataStructure? .
Les classes internes peuvent être utilisées pour implémenter des classes utilitaires
semblables à celle présentée dans l'exemple ci-dessus. Si vous prévoyez de manipuler les évènements
d'une interface utilisateur, vous devez savoir comment utiliser les classes internes car le mécanisme de traitement
des évènements fait largement appel à elles.
Les Classes Internes Locales et Anonymes
Il existe deux autres types de classes internes. Vous pouvez déclarer une classe interne à l'intérieur du corps d'une méthode. Cette classe est connue sous le nom de ''classe interne locale''. Vous pouvez aussi déclarer une classe interne à l'intérieur du corps d'une méthode sans la nommer. Ces classes sont connues sous le nom de ''classes internes anonymes''. Vous rencontrerez ces classes dans la programmation Java avancée.
Les Modificateurs
Vous pouvez utiliser les mêmes modificateurs pour les classes internes que ceux que vous
utilisez pour d'autres membres de la classe externe. Par exemple, vous
pouvez utiliser les spécificateurs d'accès - public, private et protected- afin de
restreindre l'accès aux classes internes, comme vous le faites pour les autres membres de la classe.
Résumé des Classes Imbriquées
Une classe définie dans une autre classe est appelée une classe imbriquée. Comme les autres membres d'une classe, une classe imbriquée peut être déclarée statique ou non. Une classe imbriquée non-statique est appelée une classe interne. Une instance de la classe interne ne peut exister que dans une instance de sa classe englobante et a accès aux membres de sa classe englobante, même s'ils sont déclarés private.
Le tableau suivant indique les types de classes imbriquées:
{| border=1
|+ '''Types des classes imbriquées'''
! '''Type'''!! '''Portée'''!! '''Interne'''
|-
| classe imbriquée statique|| membre|| Non
|-
| classe interne (non statique)|| membre|| Oui
|-
| classe locale|| local|| Oui
|-
| classe anonyme|| seulement l'endroit où elle est définie|| Oui
|}
les Types Enum (Java 5)
Un type enum est un type dont les ''champs'' se composent d'un ensemble fixe de constantes. Un des exemples les plus courants est les directions de boussole (valeurs de NORD, SUD, EST, OUEST), et les jours de la semaine.
Parce qu'ils sont des constantes, les noms de champs d'un type enum sont en majuscules.
Dans le langage de programmation Java, vous définissez un type enum en utilisant le mot-clé '''enum'''. Par exemple, vous voudriez spécifier enum type représentant les jours de la semaine comme suit:
Public enum Jour (
DIMANCHE, LUNDI, MARDI, MERCREDI,
JEUDI, VENDREDI, SAMEDI
)
Vous devriez utiliser les types enum à chaque fois que vous avez besoin de représenter un ensemble fixe de constantes. Cela inclut les types enum naturels tel que les planètes de notre système solaire et les ensembles de données dont vous connaissez toutes les valeurs possibles au moment de la compilation( par exemple, les choix d'un menu, les drapeaux de la ligne de commande, et ainsi de suite).
Voici du code qui vous montre comment utiliser l'enum Jour définis ci-dessus:
public class EnumTest? {
Day day;
public EnumTest?(Day day) {
this.day = day;
}
public void tellItLikeItIs() {
switch (day) {
case MONDAY: System.out.println("Mondays are bad.");
break;
case FRIDAY: System.out.println("Fridays are better.");
break;
case SATURDAY:
case SUNDAY: System.out.println("Weekends are best.");
break;
-
-
-
- default
- System.out.println("Midweek days are so-so."); break; } }
public static void main(String[] args) {
EnumTest? firstDay = new EnumTest?(Day.MONDAY);
firstDay.tellItLikeItIs();
EnumTest? thirdDay = new EnumTest?(Day.WEDNESDAY);
thirdDay.tellItLikeItIs();
EnumTest? fifthDay = new EnumTest?(Day.FRIDAY);
fifthDay.tellItLikeItIs();
EnumTest? sixthDay = new EnumTest?(Day.SATURDAY);
sixthDay.tellItLikeItIs();
EnumTest? seventhDay = new EnumTest?(Day.SUNDAY);
seventhDay.tellItLikeItIs();
}
}
La sortie est:
Mondays are bad.
Midweek days are so-so.
Fridays are better.
Weekends are best.
Weekends are best.
Les types enum de Java sont beaucoup plus puissants que leurs homologues des autres langages. La déclaration d'un type enum définit
une ''classe'' (appelé un ''type enum''). Le corps de la classe enum peut contenir
des méthodes et d'autres champs. Le compilateur ajoute
automatiquement certaines méthodes spéciales quand il crée un enum.
Par exemple, ils ont une méthode statique de valeurs qui renvoie un
tableau contenant toutes les valeurs de l'enum dans l'ordre où elles ont été
déclarées. Cette méthode est couramment utilisée en combinaison avec la boucle
for-each afin de parcourir les valeurs d'un type enum. Par
exemple, ce code de la classe Planet ci dessous itère sur toutes
les planètes du système solaire.
For (Planet p: Planet.values ()) (
System.out.printf ( "Votre poids est le% s% f% n",
P, p.surfaceWeight (masse));
)
'''Note''': Tous les enums étendent implicitement java.lang.Enum. Du moment que
Java ne supporte pas l'héritage multiple, un enum ne peut étendre autre chose d'autres.
Dans l'exemple suivant, Planet est un type enum qui représente les planètes du système solaire. Ils
sont définis avec comme propriétés une constante masse et rayon.
Chaque constante de l'enum est déclarée avec des valeurs pour les paramètres
de masse et le rayon. Ces valeurs sont transmises au constructeur lorsque la constante est créée. Java exige que les constantes soit définies
en premier lieu, avant les champs ou les méthodes. Aussi, quand il
y a des champs et des méthodes, la liste des constantes enum doit se
terminer par un point-virgule.
'''Note''': Le constructeur
d'un type enum doit être de visibilité package-private ou private. Il crée
automatiquement les constantes qui sont définies au début du corps de l'enum. Vous ne pouvez pas invoquer un constructeur d'un enum vous-même.
En plus de ses propriétés et de son constructeur, Planet a des méthodes qui
vous permettent de récupérer la surface de gravité et le poids d'un
objet sur chaque planète. Voici un exemple de programme qui prend votre
poids sur terre (dans n'importe quelle unité) et calcule et affiche
votre poids sur toutes les planètes (dans la même unité):
public enum Planet {
MERCURY (3.303e+23, 2.4397e6),
VENUS (4.869e+24, 6.0518e6),
EARTH (5.976e+24, 6.37814e6),
MARS (6.421e+23, 3.3972e6),
JUPITER (1.9e+27, 7.1492e7),
SATURN (5.688e+26, 6.0268e7),
URANUS (8.686e+25, 2.5559e7),
NEPTUNE (1.024e+26, 2.4746e7);
private final double mass; // in kilograms
private final double radius; // in meters
Planet(double mass, double radius) {
this.mass = mass;
this.radius = radius;
}
private double mass() { return mass; }
private double radius() { return radius; }
// universal gravitational constant (m3 kg-1 s-2)
public static final double G = 6.67300E-11;
double surfaceGravity() {
return G * mass / (radius * radius);
}
double surfaceWeight(double otherMass) {
return otherMass * surfaceGravity();
}
public static void main(String[] args) {
double earthWeight = Double.parseDouble(args[0]);
double mass = earthWeight/EARTH.surfaceGravity();
for (Planet p : Planet.values())
System.out.printf("Your weight on %s is %f%n",
p, p.surfaceWeight(mass));
}
}
Si vous exécutez Planet.class à partir de la ligne de commande avec un argument de 175, vous aurez l'affichage suivant:
$ java Planet 175
Your weight on MERCURY is 66.107583
Your weight on VENUS is 158.374842
Your weight on EARTH is 175.000000
Your weight on MARS is 66.279007
Your weight on JUPITER is 442.847567
Your weight on SATURN is 186.552719
Your weight on URANUS is 158.397260
Your weight on NEPTUNE is 199.207413
Les Annotations (Java 5)
Les ''Annotations'' fournissent des données sur un programme qui ne fait pas partie du programme lui-même. Ils n'ont pas d'effet direct sur le fonctionnement du code qu'ils annote.
Les annotations ont un certain nombre d'utilisations, notamment:
* '''Information pour le compilateur''' : Les annotations peuvent être utilisées par le compilateur pour détecter les erreurs ou supprimer les avertissements.
* '''Compiler-time and deployment-time processing''' : Les outils logiciels peuvent traiter les informations relatives aux annotations pour générer du code, des fichiers XML, etc.
* '''Durée de traitement''' : Quelques annotations sont disponibles pour être examinées au moment de l'exécution.
Les annotations peuvent être appliquées à un programme dans des déclarations de classes, de champs, de méthodes et d'autres éléments du programme.
L'annotation apparaît en premier, souvent (par convention) sur sa propre ligne, et peut inclure des ''éléments'' avec valeurs nommées ou non:
@Author(
name = "Benjamin Franklin",
date = "3/27/2003"
)
class MyClass?() { }
ou
@SuppressWarnings(value = "unchecked")
void myMethod() { }
S'il n'y a qu'un seul élément nommé «value», alors le nom peut être omis, comme dans:
@SuppressWarnings("unchecked")
void myMethod() { }
De plus, si une annotation n'a pas d'éléments, les parenthèses peuvent être omises, comme dans:
@Override
void mySuperMethod() { }
La Documentation
De nombreuses annotations remplacent ce qui, autrement, aurait été des commentaires dans le code.
Supposons qu'un groupe de logiciels a traditionnellement commencé le corps de chaque classe avec des commentaires fournissants d'importantes informations :
public class Generation3List? extends Generation2List? {
// Author: John Doe
// Date: 3/17/2002
// Current revision: 6
// Last modified: 4/12/2004
// By: Jane Doe
// Reviewers: Alice, Bill, Cindy
// class code goes here
}
Pour ajouter cette même méta-donnée avec une annotation, vous devez d'abord définir le ''type d'annotation''. La syntaxe pour faire cela est:
@interface ClassPreamble? {
String author();
String date();
int currentRevision() default 1;
String lastModified() default "N/A";
String lastModifiedBy() default "N/A";
String[] reviewers(); // Note use of array
}
La définition du type de l'annotation ressemble un peu à la définition d'une
interface où le mot-clé '''interface''' est précédé par le caractère @ (@ =
"AT" comme dans Annotation Type). Les types Annotations sont, en fait,
une forme d'''interface'', qui sera traitée dans une prochaine leçon.
Pour l'instant, vous n'avez pas besoin de comprendre les interfaces.
Le corps de la définition de l'annotation ci-dessus contient les déclarations des ''éléments du type annotation''
, qui ressemblent beaucoup à celles des méthodes. Notez qu'elles peuvent définir des valeurs optionnelles par défaut.
Une fois le type d'annotation définit,
vous pouvez utiliser les annotations de ce type, avec des valeurs remplies, comme ceci:
@ClassPreamble (
author = "John Doe",
date = "3/17/2002",
currentRevision = 6,
lastModified = "4/12/2004",
lastModifiedBy = "Jane Doe"
reviewers = {"Alice", "Bob", "Cindy"} // Note array notation
)
public class Generation3List? extends Generation2List? {
// class code goes here
}
'''Note:''' Pour permettre aux informations dans @ClassPreamble d'apparaître dans la
documentation Javadoc générée, vous devez annoter la définition de
@ClassPreamble elle-même avec l'annotation @Documented :
// import this to use @Documented
import java.lang.annotation.*;
@Documented
@interface ClassPreamble? {
// Annotation element definitions
}
Les Annotations Utilisées par le compilateur
Il existe trois types d'annotations qui sont prédéfinies par la spécification du langage lui-même :
@Deprecated, @Override, et @SuppressWarnings.
'''@Deprecated''' : l'annotation @Deprecated indique que l'élément marqué est ''obsolète'' ou ''déprécié'' et ne doit plus être utilisé. Le compilateur génère un avertissement chaque fois qu'un programme utilise une méthode, une classe, ou un champs avec l'annotation @Deprecated. Quand un élément devient obsolète, il devrait être également documenté à l'aide du tag de la Javadoc @deprecated , comme illustré dans l'exemple suivant. L'utilisation du symbole "@" dans les commentaires Javadoc et dans les annotations n'est pas un hasard, ils sont liées conceptuellement. Notez également que le tag de la Javadoc commence par une minuscule "d" alors que l'annotation commence par une majuscule "D".
// Javadoc comment follows
/**
* @deprecated
* explanation of why it was deprecated
*/
@Deprecated
static void deprecatedMethod() { }
}
'''@Override''' : l'annotation @Override informe le compilateur que l'élément est destiné à surcharger un élément déclaré dans une superclasse (la surcharge des méthodes sera abordée dans le cours intitulé '''''Interfaces et Héritage''''').
/ / Marque méthode comme méthode d'une classe parente
/ / Qui a été battu en brèche
@ Override
Int overriddenMethod () ()
Il n'est pas indispensable d'utiliser cette annotation lors de la surcharge d'une méthode, mais elle permet d'éviter les erreurs. Si une méthode marquée avec @Override ne surcharge pas correctement une des méthodes de la superclasse, le compilateur génère un message d'erreur.
'''@SuppressWarnings''' : l'annotation @SuppressWarnings indique au compilateur de supprimer les avertissements spécifiques qu'il aurait autrement généré. Dans l'exemple ci-dessous, une méthode dépréciée est utilisée et le compilateur devrait normalement générer un avertissement. Cependant, dans ce cas, l'annotation conduit à la suppression de l'avertissement.
/ / Utiliser une méthode obsolète et dites -
/ / Compilateur de ne pas générer un avertissement
@ SuppressWarnings? ( "deprecation")
Void useDeprecatedMethod () (
ObjectOne?.deprecatedMethod (), / / deprecation avertissement - supprimé
)
Chaque avertissement du compilateur appartient à une catégorie. La Spécification du langage Java liste deux catégories: "deprecation" et "unchecked" . L'avertissement "unchecked" peut se produire lorsque l'interfaçage avec le code écrit avant l'arrivée des Generics (discuté dans le cadre du cours intitulé «Generics»). Pour supprimer plus d'une catégorie d'avertissements, utilisez la syntaxe suivante:
@ SuppressWarnings? (( "unchecked", "deprecation"))
Les Annotations d'exécution
Les utilisations les plus avancées des annotations incluent l'écriture d'une ''annotation processeur'' qui peut lire un programme Java et prendre des mesures en se basant sur ces annotations. Elle pourrait, par exemple, générer du code source auxiliaire, soulageant le programmeur d'avoir à créer du code standard qui suit toujours des patterns prévisibles. Pour faciliter cette tâche, la version 5.0 du JDK inclut un outil d'annotation, appelé '''''apt'''''. Dans la version 6 du JDK, la fonctionnalité d'apt est devenu un élément standard du compilateur Java.
Pour rendre l'information d'annotation disponible au moment de l'exécution, le type annotation lui même doit être annotée avec @Retention(RetentionPolicy.RUNTIME), comme suit:
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@interface AnnotationForRuntime {
// Elements that give information
// for runtime processing
}
Les Interfaces et l'Héritage (En cours de traduction)
Cette leçon décrit les interfaces, ce qu'elles sont, la raison pour laquelle vous désirez en écrire une, et comment en écrire une. Cette leçon décrit également la manière dont vous pouvez dériver une classe d'une autre. Entre autres, comment une ''sous-classe'' peut hériter des champs et des méthodes d'une ''superclasse''. On y apprend que toutes les classes sont dérivées de la classe Obejct, et comment modifier les méthodes qu'une sous-classe hérite de superclasses.
Les Interfaces
Il y a un certain nombre de situations dans le génie logiciel où il est important que des groupes différents de programmeurs acceptent un «contrat» qui précise la façon dont leur logiciel interagit. Chaque groupe devrait être capable d'écrire son code sans aucune connaissance de la façon dont le code des autres groupes a été écrit . De manière générale, les ''interfaces'' sont de tels contrats.
Par exemple, imaginez une société futuriste où les voitures robots contrôlées par ordinateur de transportent des passagers à travers les rues de la ville sans opérateur humain. Les constructeurs automobiles écrivent des logiciels (Java, bien sûr) qui exploite l'automobile : démarrer, accélérer, tourner à gauche, et ainsi de suite. Un autre groupe industriel, les fabricants d'appareils d'orientation électronique , fabriquent des systèmes informatiques qui reçoivent les données de la position GPS (Global Positioning Satellite), et de transmission sans fil de conditions de circulation et utilisent ces informations pour conduire la voiture.
Les constructeurs automobiles doivent publier une interface industrielle standard qui énonce en détail les méthodes qui peuvent être invoquées pour faire avancer la voiture (n'importe quelle voiture, à partir de n'importe quel fabricant). Les fabricants d'orientation peuvent ensuite écrire un logiciel qui invoque les méthodes décrites dans l'interface de commande de la voiture. Aucun groupe industriel n'a besoin de savoir ''comment'' le logiciel d'un autre groupe est implémenté En fait, chaque groupe considère ses logiciels hautement propriétaires et se réserve le droit de le modifier à tout moment, tant qu'il continue d'adhérer à l'interface publiée.
= Les Interfaces en Java =
Dans le langage de programmation Java, une ''interface'' est un type référence, semblable à une classe, qui ne peut contenir ''que'' des constantes, des signatures de méthodes, et des types imbriqués. Il n'existe pas de corps pour les méthodes. Les interfaces ne peuvent pas être instanciées (elles ne peuvent qu'être ''implémentées'' par des classes ou ''étendues'' par d'autres interfaces. L'héritage sera abordé plus loin dans cette leçon.
Définir une interface est similaire à la création d'une nouvelle classe:
public interface OperateCar {
// constant declarations, if any
// method signatures
int turn(Direction direction, // An enum with values RIGHT, LEFT
double radius, double startSpeed, double endSpeed);
int changeLanes(Direction direction, double startSpeed, double endSpeed);
int signalTurn(Direction direction, boolean signalOn);
int getRadarFront(double distanceToCar, double speedOfCar);
int getRadarRear(double distanceToCar, double speedOfCar);
......
// more method signatures
}
Notez que les signatures des méthodes n'ont pas d'accolades et se terminent par un point-virgule.
Pour utiliser une interface, vous écrivez une classe qui ''implémente''
l'interface. Quand une classe instanciable implémente une interface,
elle fournit un corps à la méthode pour chacune des méthodes déclarées
dans l'interface. Par exemple,
public class OperateBMW760i implements OperateCar {
// the OperateCar method signatures, with implementation --
// for example:
int signalTurn(Direction direction, boolean signalOn) {
//code to turn BMW's LEFT turn indicator lights on
//code to turn BMW's LEFT turn indicator lights off
//code to turn BMW's RIGHT turn indicator lights on
//code to turn BMW's RIGHT turn indicator lights off
}
// other members, as needed -- for example, helper classes
// not visible to clients of the interface
}
Dans l'exemple de la voiture robot ci-dessus, c'est les constructeurs automobiles qui implémenteront l'interface. L'implémentation de Chevrolet sera sensiblement différente de celle de Toyota, bien sûr, mais les deux fabricants adhèreront à la même interface. Les fabricants de guidage, qui sont les clients de l'interface, vont construire des systèmes qui utilisent des données GPS sur une voiture de location,des cartes numériques des rues, des données de trafic afin de conduire la voiture. Ce faisant, les systèmes de guidage invoqueront les méthodes des interfaces: tourner, changer de voie, freiner, accélérer, et ainsi de suite.
= Les Interfaces comme APIs =
L'exemple de la voiture robot montre une interface utilisée comme une ''interface de programmation (Application Programming Interface (API))'' standard de l'industrie . Les API sont également fréquentes dans les produits logiciels commerciaux. Habituellement, une entreprise vend un package logiciel qui contient des méthodes complexes qu'une autre entreprise souhaite utiliser dans ses propres produits logiciels. Un exemple serait un ensemble de méthodes de traitement d'image numérique, qui sont vendus à des sociétés qui conçoivent des programmes graphiques pour l'utilisateur final . La société de traitement d'images écrit ses classes afin d'implémenter une interface, qu'elle rendra publique à ses clients. Ensuite, l'entreprise de graphisme invoque les méthodes de traitement d'images en utilisant les signatures et les types de retours définis dans l'interface. Tant que l'API de traitement d'images de l'entreprise est rendue public (à ses clients), son implémentation est gardée secrète (en fait, elle peut modifier ultérieurement l'implémentation , tant qu'elle continue à implémenter l'interface originale que ses clients ont invoqué).
= Les Interfaces et l'Héritage Multiple =
L'Héritage
|