Classes et Objets

La programmation dans un style objet utilise la création dynamique d'objets. Lorsque l'on utilise un langage objet comme Java ou C++, ces objets sont les instances d'une classe.
Par exemple, il est apparu dans le code de Conversion.java qu'il était intéressant de disposer d'objets représentant des devises, composés d'un nom et d'un taux de change en Euro.
Le code correspondant est :
class Devise {
    double tauxDeChangeEnEuro;
    String nom;
}
tauxDeChangeEnEuro et nom sont les champs, aussi appelés variables d'instance de la classe Devise.
On peut alors créer des objets de la classe Devise à l'aide de l'opérateur new :
Devise franc = new Devise();
franc.tauxDeChangeEnEuro = 6.55957;
franc.nom = "Francs";
Devise() est un constructeur, et dans ce cas précis le constructeur fourni par défaut, sans argument (on parle de constructeur vide). Un tel constructeur dans le cas de Devise n'est pas souhaitable car on va répéter après chaque instantiation les instructions  d'affectation des champs tauxDeChangeEnEuro et nom. Il convient donc de fournir un constructeur prenant en paramètre les valeurs à affecter aux champs.
D'autre part, l'encapsulation de données préconise que les classes utilisant la classe Devise ne puissent avoir accès directement à ses données. Le fait d'interdire cet accès direct permettra de garantir la possibilité de représenter les données sous une forme différente sans avoir à réécrire les classes clientes. Il est donc nécessaire d'interdire l'utilisation directe des champs de Devise par une classe cliente, grâce au mot clé private et donc en contrepartie, de fournir des méthodes permettant de récupérer les données d'une devise et de les modifier si besoin.
Pour terminer, il paraît naturel de fournir directement une méthode de conversion en Euro et une méthode de conversion depuis l'Euro comme méthode de la classe Devise.

Contrôle d'accès

Les classes disposent de deux niveaux de contrôle d'accès. De plus, les différents éléments d'une classe (variables et méthodes) possèdent eux-mêmes quatre niveaux de contrôle d'accès. Il faut remarquer que déclarer public un élément d'une classe qui ne l'est pas ne modifie pas l'accessibilité de l'élément.

Variables et méthodes de classe et d'instance

Lorsqu'un objet est instancié, ses champs sont accessibles à partir d'un de ses identificateurs associé à l'opérateur ".".
Par exemple,
Devise d = new Devise();
d.nom = "Francs";
Si aucune valeur d'initialisation n'est précisée, la valeur des champs lors de l'instantiation est selon leur type false, 0 ou null.
De même, l'appel d'une méthode d'instance d'une classe doit être fait à travers l'objet concerné, via l'opérateur ".". Dans le code d'une méthode d'instance, l'appel d'une méthode d'instance ou l'utilisation d'un champ, sans précision de l'objet concerné, porte sur l'objet à partir duquel on a appelé la méthode. De plus, si un champ n'est pas accessible par ce moyen car "caché" par un paramètre portant le même nom, il peut être utilisé à l'aide du mot-clé this et de l'opérateur ".".
Certaines variables et méthodes peuvent être communes à toutes les instances, c'est-à-dire ne pas concerner une instance en particulier. Ce sont les variables et méthodes de classes, qui sont définies à l'aide du mot-clé static. Dans une classe, ses propres variables et méthodes de classes peuvent être utilisées directement. A partir d'une autre classe, elles devront être utilisées à l'aide de l'opérateur "." précédé du nom de la classe ou d'un identificateur d'une instance de cette classe.  Toutefois, il est recommandé, pour une question de lisibilité, de préférer l'usage du nom de la classe plutôt qu'un identificateur d'instance, qui peut laisser penser qu'il s'agit d'une variable ou d'une méthode d'instance et donc que le choix de l'identificateur est important.
Plusieurs méthodes peuvent avoir le même identificateur, avec des signatures (liste de paramètre) différentes. C'est ce que l'on appelle la surcharge. Le nom complet d'une méthode est donc son identificateur + sa signature. Deux méthodes avec le même nom et des signatures différentes peuvent avoir des retours de type différent.

Bloc d'initialisation statique

Il est possible dans le code d'une classe de déclarer des blocs static qui seront exécutés au chargement de la classe.

Utilisation de final

Le mot clé final devant un élément signifie que celui-ci ne peut être modifié.
Dans le cas d'une variable de classe, il s'agira donc d'une constante dont la valeur doit être spécifiée, éventuellement par un appel de méthode, à la déclaration.
Pour les variables d'instance, il s'agit de champs dont la valeur doit être spécifiée soit à la déclaration, soit dans les premières instructions des constructeurs. Ces champs ne pourront plus être modifés par la suite. Cette contrainte a pour effet secondaire que, si l'on fournit plusieurs constructeurs, il est impossible que l'un d'eux puisse en utiliser un autre, ce qui nuit à la factorisation du code. Si les variables sont privées, il est alors généralement préférable de renoncer à l'utilisation de final. Notons que l'aspect constant d'une variable ne concerne que sa valeur. Si cette valeur est une référence, l'objet référencé pourra être modifié : s'il s'agit d'une instance, il sera toujours possible de modifier l'un de ses champs et s'il s'agit d'un tableau la valeur d'un de ses éléments.
Pour les méthodes, final aura pour effet d'interdire à une classe héritière de redéfinir la méthode.

Ordre des mots-clés

Il n'y a pas d'ordre d'utilisation des mots-clés imposés par le compilateur. Toutefois, il est important pour la lisibilité de garder toujours le même ordre, et l'ordre préconisé est celui mettant en avant l'importance du contrôle d'accès :
<contrôle d'accès> <static> <final> type identificateur

Object

Tout objet est un Object ! Ces qui a deux conséquences :
la première est que si une méthode doit porter sur n'importe quel objet, le paramètre déclaré aura pour type Object.
La deuxième conséquence est que tout objet possède, par un mécanisme d'héritage implicite, les méthodes suivantes : Enfin, la classe Object fournit également les méthodes
finalize(), liée à la destruction d'un objet par le ramasse-miette,
notify(), notifyAll() , wait(), wait(long) et wait(long, int) liées à l'utilisation des processus légers (thread).

Destruction d'objets

Java utilise un ramasse-miette pour détruire les objets. Le ramasse-miette a pour but de récupérer la mémoire utilisée par des objets qui ne sont plus référencés depuis la pile d'exécution. L'utilisation de cette technique supprime ainsi l'une des principales causes de bogues.
Il arrive parfois lors de la suppression d'un objet qu'il faille faire d'autres actions que récuperer sa mémoire et détruire des objets référencés uniquement à partir de cet objet. C'est par exemple le cas lorsque l'objet est un identificateur de flot de caractères obtenu par l'ouverture d'un fichier en lecture. Sa destruction doit entraîner la fermeture du fichier. Ceci peut être fait grâce à la méthode finalize() qui est appelée depuis un objet quand celui-ci est détruit.

A lire