Si vous avez lu le tutoriel précédent, vous savez que le langage de programmation Java ne peut manipuler qu’un nombre fini de types de variables (des nombres entiers, réels, des caractères). Cependant ces types sont assez restrictif quand on cherche à manipuler de très gros élements comme des images. Pour pouvoir traiter des objets complexes qui necessitent plusieurs tableaux de variables de types differents, les informaticiens ont permis la création de variables personnalisées qui sont formées de plusieurs types de variables, parce qu’ils sont originaux, on appelle ces variables les objets. Une image en niveau de gris (image décomposées en pixels chacun associé à un nombre entier entre 0 et 255 correspondant à un gris, avec 0 le blanc et 255 le noir) par exemple peut être vu comme une chaine de caractere contenant son titre, deux entiers indiquant ses dimensions et d’un tableau d’entiers contenant les valeurs en niveau de gris de ses pixels.
Il existe quelque particularités sur les objets. Tout d'abord ils peuvent se déclarer comme des variables, on utilise à ce moment là leur nom, par exemple:
Image Loutre;
créera une image qui sera référencé dans le reste du programme par Loutre. Il existe une convention qui veut que les variables objets commencent nécéssairement par une majuscule, de façon à pouvoir efficacement les distinguer des variables standards. Cependant, comme ces variables sont personnelles, il faut tout d'abord les définir. Pour chaque variable objet, il existe donc un fichier qui définit ses propriétés, c'est à dire les variables primaires dont il est composé et les fonctions que l'on faire agir sur cet opérateur (il est évident qu'un compilateur aura du mal à comprendre nativement “Image + Image;”). Quand on utilise ces fonctions sur un objet, on devra utiliser une syntaxe du type:
Loutre.donnerunnom("SuperLoutre");
(cette fonction par exemple agira sur l'objet définit précédemment Loutre, et lui donnera le nom “SuperLoutre”).
On appelle l'ensemble des propriétés et des fonctions la classe de l'objet. Si on reprends l'exemple de l'image dont j'ai parlé précédemment, sa classe serait alors:
public class Image{ private int largeurenpixel; private int longueurenpixel; private int[] tableaudesvaleursimages; private String nomImage; public void definirLargeurEnPixel(int largeur){ // Fonction permettant à un codeur de definir la largeur de l'image en pixel } public void definirLongueurEnPixel(int longueur) { // Fonction permettant à un codeur de definir la longueur de l'image en pixel } public void definirValeursImages(int[] valeurs){ // Fonction permettant à un codeur de définir les valeurs de l'image } public void definirTitreImage(String Image) { // Fonction permettant de definir le titre de l'image } public void afficher() { // Fonction permettant d'afficher l'image } public void fermer(){ // Fonction permettant de fermer l'image } }
On n'a ici pas détaillé les codes de chaque fonction. Vous remarquerez sans doute que chaque variable caracteristique de l'objet est précédé de private et qu'il existe une fonction permettant de definir chacune de ses variables (on aurait aussi pu faire une fonction permettant de définir toutes les variables d’un seul coup). Ceci est une tradition de codeur pour éviter des tas de problèmes: quand on utilise un objet on ne doit pouvoir en modifier ou en afficher les attributs que par l'utilisation de fonctions (que l’on appelle alors accesseurs ou des mutateurs selon leur rôle). On appelle ce principe l'encapsulation (vous pourrez avoir plus de détails et une description plus rigoureuse de ce principe si vous allez sur le tutoriel sur le Java d'ImageJ. Les private restreignent donc l'accès aux variables de façon directe, mais tout ce qui est précédé par un public pourra être utilisé dans le code. Par exemple, il sera impossible de faire la chose suivante:
Image Loutre; Loutre.longueurenpixel = 3;
Très simplement parce que la variable longueurenpixel est protégée. Pour définir une image il nous faudra faire:
Image Loutre; Loutre.definirTitreImage("Une Image de Loutre"); Loutre.definirLargeurEnPixel(2); Loutre.definirLongueurEnPixel(2); Loutre.definirValeursImages([1,1,1,1]);
Ce qui créera alors (si les fonctions ont été correctement codées) une image avec pour titre “Une image de Loutre”, de taille 2*2 pixels chacun de même couleur.
Le concept est fabuleux parce qu’il est à partir de là possible de définir des objets à partir en utilisant d’autres objets comme variables primaires (c’est d’ailleurs un cas assez fréquent).
Parfois on peut reprendre un objet pour en faire un legerement different, avec plus de variables et de fonctions. Parce qu’on est fainéant et on fait cela en rajoutant le nom de l’objet que l’on souhaite copier en rajoutant le nom de la classe de l’objet précédé de Implements dans la ligne de déclaration de la classe de notre nouvel objet, par exemple:
public class Loutre Implements Animal { // Variables et fonctions de loutre }
Nous permet de definir un nouvel objet Loutre à partir d’un objet de type Animal, ce qui est logique vu que dans la vraie vie, une Loutre est un animal.
Voilà pour les bases théoriques sur les objets dont vous aurez besoin. Pour vous tester je vous conseille de reprendre les petits plugins que j’ai laissé dans le dossier et de tenter d’identifier tous les elements. Pour vraiment verifier, je vous conseille de regarder ce site:
http://imagej.nih.gov/ij/developer/source/index.html
qui contient l’ensemble du code de toutes les classes du logiciel. Ne paniquez pas devant leur nombre, nous en utiliserons uniquement 5 ou 6. Les plus courantes, que vous devriez essayer d’analyser (en gros, il y a beaucoup de choses assez compliquée dedans que nous n’utiliserons pas), je vous conseille surtout d’essayer de distinguer les variables propres des objet, le code correspondant à leur fonctions propres, et celles qui sont libres d’accès pour le code. Vous pouvez aussi essayer de deviner ce que font certaines fonctions propres.
.Les classes que nous seront amenées à utiliser sont: