Java/Classes et objets
Introduction
modifierLe terme orienté objet souvent lié au langage Java vient d’une part du fait que l’on peut :
- Créer des objets
- Libérer des objets non utilisés à l’aide d’un ramasse-miettes
Un objet est une instance d’une classe, qui est l’outil fondamental de programmation en Java. Une classe peut aussi être considérée comme une description de ce qu’il faut faire pour créer un objet. Les classes sont composées de méthodes et d’attributs qui peuvent être public, private ou protected.
Les différents mots clés concernant l'accessibilité sont les suivants :
- Aucun mot clé: accessible par les classes du même paquetage ou package ;
- Public: accessible par toutes les classes ;
- Protected: accessibles par toutes les classes héritées et les classes du même paquetage, inaccessibles par les autres ;
- Private: inaccessible par toute autre classes.
Ces termes sont utilisables aussi bien sur les méthodes que sur les variables.
Le terme static permet aussi de spécifier des variables de classe ou des méthodes de classe.
Créer une classe permettant de créer des objets
modifierLa première étape pour créer de nouveaux objets est de créer une nouvelle classe de façon particulière. C’est ce que l’on va voir avec l'exemple de la classe Point.
public class Point{
public static double dimension = 2 ;
//Variable de classe
private double x ;
private double y ;
//Variables d'instance
public Point(){
this(0,0) ;
}
//Constructeur par défaut
public Point(double x , double y){
this.setX(x) ;
this.setY(y) ;
}
//Constructeur avec argument
public double getX(){
return this.x ;
}
public void setX(double x){
this.x = x ;
}
//Accesseurs correspondant à la variable x.
public double getY(){
return this.y ;
}
public void setY(double y){
this.y = y ;
}
//Accesseurs correspondant à la variable y.
public void symetrieSelonX(){
this.y = -this.y;
}
public void symetrieSelonY(){
this.x = -this.x;
}
public static double quelleDimension(){
return dimension ;
}
}
Cet exemple mérite des éclaircissements qui vont être donnés dans la suite.
Variables de classe/d'instance
modifierDans l'exemple de classe que nous avons ici, il apparaît une variable de classe et deux variables d'instance. Quelle est donc la différence entre ces deux types de variables lors de la création d’un objet ?
La variable de classe n'est en rapport avec aucun objet, elle ne dépend d'aucun objet, le plus souvent elle ne sera pas modifiée au cours de l'exécution du programme. Dans notre exemple, elle sera accessible dans la classe directement par son nom et dans d'autres classes par Point.dimension ou par la méthode statique appelée par Point.quelleDimension().
Les variables d'instance servent à représenter l’objet informatiquement. Ainsi, il est possible de représenter tous les objets réels par un ensemble de données de bases. Ceci s’appelle l'agrégation. C’est la méthode la plus utilisée pour créer des objets simples. Ici, notre point est représenté par deux double qui sont dans la réalité ses coordonnées. Ces deux variables sont déclarées private par convention, en effet, on ne souhaite pas que d'autres classes puissent accéder directement à ces données. Chaque instance de l’objet (ici chaque Point) aura des valeurs différentes pour ces variables, elles sont réellement sa représentation, et contrairement aux variables de classes, ce sont bien ces données-là qui seront manipulées lors de l'exécution du programme.
Constructeur
modifierLe constructeur comme son nom l'indique est la méthode qui sert à créer une instance d’un objet. Sa déclaration est particulière puisqu’un constructeur ne retourne rien (on ne peut pas avoir return dans un constructeur). On peut remarquer ici qu’il y a deux constructeurs :
- le constructeur par défaut, sans argument, il se contentera d'appeler le deuxième constructeur avec 0 et 0 en argument.
- le constructeur avec argument qui permet de créer un point avec les coordonnées x et y.
Plusieurs choses nouvelles apparaissent dans ces constructeurs :
- La première, qui n’est pas des plus simples à comprendre, est l'apparition de this. Ce terme est le plus important de la programmation par objet en Java. En effet, ce terme représente la future instance de l'objet. Ainsi this pointe déjà vers une instance de l'objet. La première utilisation que l’on peut remarquer, est celle qui en est faite dans le constructeur avec argument, où les arguments portent le même nom que les variables d'instance mais ces dernières sont différenciées par l'apparition de this devant.
- La deuxième chose importante est le chaînage des constructeurs. Il peut paraître étrange d’avoir plusieurs constructeurs mais ils se différencient parfaitement par leurs arguments, il est donc possible d’avoir toute une panoplie de constructeurs. Le chaînage des constructeurs est donc le fait de faire appel à un constructeur dans un constructeur. On remarque alors que le constructeur par défaut fait appel au constructeur avec argument par this(0,0) avec les arguments 0 et 0.
- La dernière chose est le fait de ne pas faire appel directement aux variables d'instances mais plutôt aux accesseurs. Même si ici ce n’est pas franchement utile, on retiendra quand même cela comme une convention car cela permet de changer de représentation (changer les variables d'instance) sans ne jamais changer les constructeurs. Un exemple sera donné dans la partie consacrée aux accesseurs.
Remarque : il n’est pas obligatoire d’avoir un constructeur pour créer des objets car Java en crée un par défaut. Cependant, ce constructeur par défaut initialisera toutes les variables d'instance à la valeur null quel que soit le type de donnée.
Il est maintenant intéressant de savoir comment utiliser ces constructeurs. Le meilleur moyen de le savoir est de créer quelques points.
Point monPoint = new Point() ;
//La création d'une instance se fait de cette manière, ici on remarque
//que Point est devenu un nouveau type de donnée, on a créé un objet.
//On a utilisé ici le constructeur par défaut, donc monPoint a pour
//coordonnées (0,0).
Point monPoint2 = new Point(2,1) ;
//On a créé ici un point de coordonnées (2,1).
Accesseurs
modifierLes accesseurs sont les méthodes, et d'ailleurs les seules, qui accèdent directement aux variables d'instance. Ainsi, ces méthodes seront utilisées dans les constructeurs, dans les méthodes d'instances, mais aussi dans toute autre méthode qui nécessitera une donnée particulière de notre objet.
Par convention, les accesseurs permettant d'accéder aux valeurs des variables d'instance ont toujours pour nom get + le nom de la variable et les accesseurs permettant de modifier les valeurs des variables d'instance set + le nom de la variable. Ainsi, il est en général très simple d’utiliser un code, même un code qui n’est pas le sien, si ces conventions sont respectées.
Le grand intérêt des accesseurs est de rendre indépendant tout le reste du code de la représentation de l'objet. Pour s'en convaincre, l'exemple des nombres complexes en représentation cartésienne puis en polaire est très bon à faire.
Méthodes de classe/d'instance
modifierLes méthodes de classe et d'instance se différencient exactement de la même manière que les variables de classe ou d'instance. Ainsi, on appelle une méthode de classe (prenons l'exemple de la classe Point) par Point.quelleDimension(). Les méthodes d'instance ne s'appliquent qu’à une instance de classe, il est donc nécessaire de créer au moins un objet pour pouvoir appeler ces méthodes.
Point monPoint = new Point(4,6) ;
//On crée un Point
monPoint.symetrieSelonX() ;
//On appelle la méthode symetrieSelonX() sur l'instance monPoint de Point.
System.out.println("L'abscisse de monPoint est : " + monPoint.getX()) ;
System.out.println("Oracle : L'abscisse de monPoint est : 4") ;
//On remarque que les accesseurs sont appelés comme des méthodes d'instance normales, et
//en effet, c'en sont.
System.out.println("L'ordonnée de monPoint est : " + monPoint.getY()) ;
System.out.println("Oracle : L'ordonnée de monPoint est : -6") ;
On a donc créé une instance à laquelle on a appliqué des méthodes.