1 Types Objets-Classes
2 Des élements plus généraux sur l'organisation des classes, la compilation etc...
3 Le cas de String : non pas un type primitif mais une classe avec des abus de syntaxes
4 Un point sur les variables et les méthodes
public class Facture{ }On définit une classe Facture ici. On va la doter d'une fonction main pour pouvoir lancer l'exécution à partir de cette classe.
public class Facture{ public static void main(String[] args) { } }
public class Facture{ public double montant; public int nbVentes; public double prixUnitaire; public static void main(String[] args) { } }
public class Facture{ public double montant; public int nbUniteesVendues; public double prixUnitaire; /*La méthode qui renvoie le Chiffre d'affaire généré par la facture*/ public double calculCA() { return prixUnitaire*nbUniteesVendues; } /*La méthode qui diminue le montant d'une remise*/ public void integrationRemise(double taux) { if(taux>=0 && taux<=1) { montant=montant-taux*montant; } } public void calculMontant() { montant=nbUniteesVendues*prixUnitaire; } /*une méthode particulière : main*/ public static void main(String[] args) { } }On constate que la déclaration d'un attribut pour la classe est de la forme :
[Visbilité] type nom
[Visbilité] type nom = valeur
public int n; private double a=0.7;
[Visbilité] type_du_retour nom_méthode(paramètres)
public void calculMontant(double remise){} private double produit(double a,int b) { return a*b; } public double produit(double a,double b) { return a*b; } public int max(int n,int m) { if(n>m) return n; else return m; }
On peut mettre un type void de retour, dans ce cas, il n'y a pas à indiquer d'instruction de retour.
Dans le cas où le type de retour n'est pas void : il faut spécifier une instruction de retour, ce peut
être une variable return x; ou bien return x*2; etc... Il faut bien sûr que le type de la variable de retour
soit le type retourné par la méthode.
Un attribut ou une méthode de visibilité private ne sont utilisables qu'au sein des méthodes de la classe dans laquelle ils sont définis.
Au contraire, les attributs et les méthodes public sont utilisables sans restriction.
Il reste à créer des objets, instances de la classe qu'on vient de créer et à manipuler les méthodes et les variables. La création d'un objet se fait par la création et l'appel particulier d'une méthode particulière le constructeur, celui-ci est une méthode du nom de la classe, ne définit pas un type de retour, a pour retour un objet de type Facture et n'est pas appellée comme les autres méthodes, son appel passant par le mot clé new
public class Facture{ public double montant; public int nbUniteesVendues; public double prixUnitaire; /*La méthode qui renvoie le Chiffre d'affaire généré par la facture*/ public double calculCA() { return prixUnitaire*nbUniteesVendues; } /*La méthode qui diminue le montant d'une remise*/ public void integrationRemise(double taux) { if(taux>=0 && taux<=1) { montant=montant-taux*montant; } } public void calculMontant() { montant=nbUniteesVendues*prixUnitaire; } /*Le constructeur*/ public Facture(int nbUnites,double prix) { nbUniteesVendues=nbUnites; prixUnitaire=prix; montant=0; } /*une méthode particulière : main*/ public static void main(String[] args) { Facture fact1,fact2;/*Declaration de variables de type Facture*/ fact1=new Facture(7,1.6);/*Instanciation en appelant le constructeur et affectation à la variable fact1*/ fact2=new Facture(3,10);/*Instanciation en appelant le constructeur et affectation à la variable fact2*/ } }On a ici crée un constructeur Facture qui affecte les variables nbUnites et prix. Dans la méthode main, on déclare des variables de type Facture : fact1 et fact2 et on ensuite, on crée des objets qu'on affecte à des variables.
Créer une classe, c'est créer un type pour lequel on peut ensuite déclarer des variables, instancier des objets et affecter des objets instanciés à des variables. Soit une variables affectée d'un objet Facture, à ce moment, il est possible de faire des opérations sur les attributs de l'objet et d'en appeller les méthodes. Quelques exemples :
Facture fact1=new Facture(4,5.5); System.out.println(fact1.nbUniteesVendues); /*Affiche 4*/ System.out.println(fact1.prixUnitaire); /*Affiche 5.5*/ System.out.println(fact1.montant); /*Affiche 0*/ double x=fact1.calculCA(); /*On affecte 5.5*4=>22 à x*/ System.out.println(x); /*Affichage de 22*/ System.out.println(fact1.montant); /*Affichage de 0*/ fact1.calculMontant(); /*Appel de la méthode de calcul du montant*/ System.out.println(fact1.montant); /*Afiichage de montant : 22*/ fact1.integrationRemise(0.05); /*Appel de la méthode d'intégration de la remise sur le montant*/ System.out.println(fact1.montant); /*Affichage de la nouvelle valeur du montant : 20.9*/Pour récupérer l'ensemble de cette classe et l'exécuter : Facture.java. Le lecteur est inviter à rajouter des instructions comme celle de l'exemple précédent dans le main() pour tester sa compréhension du fonctionnnement de la manipulation des attributs et des méthodes des objets. Note : il est possible de définir les attributs et les méthodes dans n'importe quel ordre.
int i=5; int j; j=i; j=j+1; System.out.println(i+" "+j); Facture fact1=new Facture(4,3); Facture fact2; fact2=fact1; fact2.nbUniteesVendues=fact2.nbUniteesVendues+1; System.out.println(fact1.nbUniteesVendues+" "+fact2.nbUniteesVendues);
fact2.nbUniteesVenduees=6; i=fact2.nbUniteesVendues; fact2.nbUniteesVendues=fact2.nbUniteesVendues+1; System.out.println(i+" "+fact2.nbUniteesVendues);
public Client clientFacture;
Facture.java:9: cannot resolve symbol symbol : class Client location: class Facture
public class Facture{ /*Définition des méthodes et attributs de la classe Facture, éventuellement d'une fonction main*/ } class Client{ /*Définition des méthodes et attributs de la classe Client*/ }
public class Client{ int numClient; int nbFacturesClient=0; public Client(int num) { numClient=num; } public void ajouterUneFacture() { nbFacturesClient=nbFacturesClient+1; } }
/*On crée un objet Facture*/ Facture fact1=new Facture(4,1.6); /*On crée un objet client*/ Client clt=new Client(5); /*On affecte le client à la facture*/ fact1.clientFacture=clt; /*il est alors possible d'utiliser les attributs et les méthodes du client de la facture : */ /*on change le numéro du client*/ fact1.clientFacture.num=6; /*On ajoute une facture sur le client*/ fact1.clientFacture.ajouterUneFacture();
Le constructeur provoque une initialisation par défaut des différentes variables avant l'exécution des instructions du constructeur. Les attributs numériques sont initialisées à 0. Les attributs objets sont initialisés à null, qui est la valeur d'une variable objet qui ne pointe sur rien. Les variables booléennes sont à faux. Les variables de type char sont initialisés à ' '. Ce sont ensuite les valeurs affectées dans la ligne de définition des attributs qui est prise en compte avant l'exécution des instructions du constructeur. On a en effet vu dans la définition d'une classe qu'il est possible de définir des attributs en faisant une affectation en même temps :
/*Le cas de la déclaration des attributs de classe avec affectation*/ public int nbUniteesvendues=5; public Client clientFacture=new Client(3); /*Le cas de la déclaration des attributs de classe sans affectation*/ public int nbUniteesvendues; public Client clientFacture;
public static int nbFactures=0; public Facture(int nbUnites,double prix) { nbUniteesVendues=nbUnites; prixUnitaire=prix; montant=0; nbFactures++; }
static double montantTotalFacture=0;
fact1.prixUnitaire=fact1.prixUnitaire+1.5;
private double prixUnitaire=0; public double getPrixUnitaire() { return prixUnitaire: } public void setPrixUnitaire(double nouveauPrix) { Facture.montantTotalFacture-=prixUnitaire*nbUniteesVendues; montant=nouveauxPrix*nbUniteesVendues; Facture.montantTotalFacture+=nouveauPrix*nbUniteesVendues; prixUnitaire=nouveauPrix; }
public class ClasseConstructeur { public void affiche5() { System.out.println(5); } }
public class ClasseSansConstructeur { int val=0; public ClassCOnstructeur(int n) { val=n; } public void afficheN() { System.out.println(val); } }Si on veut disposer du constructeur sans argument, il faut alors le sépcifier explicitement :
public class ClasseSansConstruceur { int val=0; public ClassCOnstructeur(int n) { val=n; } public ClassConstructeur() { val=5; } public void afficheN() { System.out.println(val); } }
Facture a,b; ... boolean bo=(a==b)bo est à vrai seulement si a et b font réference à un seul et même objet, et non pas seulement si les valeurs des champs sont les mêmes.
(new Facture(5,7.6)).calculMontant();Dans ce cas, on crée un objet sans réference qui sera éliminé lors de l'activation du ramasse-miette. Soit un autre exemple :
Facture fac1=new Facture(5,78); fac1=new Facture(6,7.8);Ici on a crée deux factures, mais on a perdu la référence sur la première : le ramasse miette pourra l'éliminer.
public class Point { private int x,y; public Point(int abs,int ord)//constructeur { x=abs; y=ord; } public void deplace(int dx,int dy)//deplace(int,int) { x+=dx; y+=dy; } public void deplace(int dx)//deplace(int) { x+=dx; } public void deplace(short dx)//dplace(short) { x+=dx; } } public class SurDef1 { public static void main(String args[]) { Point a=new Point(1,2);//appelle deplace(int,int) a.deplace(1,3);//appelle deplace(int) a.deplace(2); short p=3; a.deplace(p);//appelle deplace(short) } }En cas d'ambigüité, ie supposons la définition de :
public void deplace(int dx,byte dy)//deplace(int,byte) { x+=dx; y+=dy; } public void deplace(byte dx,int dy)//deplace(byte,int) { x+=dx; y+=dy; }Que se passe t'il alors avec le code suivant ?
int byte b; a.deplace(b,b);Ici l'appel est ambigü et provoquera une erreur de compilation.
public class Test { private int x,y; private int n; private static int m; public void incrementN(int x) { n+=x; } }Ce code ne provoque pas d'erreur ! Mais le x dans la fonction désigne t'il l'attribut de l'objet ou bien le paramètre passé à la fonction ? Il y a priorité, ici, le x est celui qui est passé en paramètre. Pour accéder la variable x de l'objet : on aurait mis this.x pour désigner le x de l'objet, Test.m pour être assuré qu'il n'y ait pas d'ambigüité. On peut tester le code suivant :
public class Test { private int x=7; private static int m=5; public void attribut(int x) { System.out.println(x); System.out.println(this.x); } public void attributClass(int m) { System.out.println(m); System.out.println(Test.m); } public static void main(String[] args) { Test t=new Test(); t.attributClass(9); t.attribut(1); } }
public class Point{ public Point(int abs,int ord) { x=abs; y=ord; } public Point() { this(0,0); } }Attention : this doit être la première instruction du constructeur si on veut appeller un autre constructeur.
class E { ... class I { ... ... } ... }
package chemin du package; import chemin du package; import chemin du package; import chemin du package; ... import chemin du package; import chemin du package; import chemin du package; [public|private] class nomClasse { }La notion de package renvoie à un ensemble de classe regroupées sous un nom : le nom du package. La notion de package est proche de la notion de bibliothèque dans les autres langages. Deux types de package : ceux qui sont pré-définis dans l'API, ceux qui sont construits par le programmeur qui sépare son programme en package (par exemple une séparation entre classes de fonctionnement et classe d'affichage pour un même logiciel).
package MonPackage; public class TestPackage{ }Si on compile cette classe, elle ne sera pas utilisable tant que non pas placée dans un repertoire MonPackage. Deux solutions :
Il existe des conventions dans la manière d'écrire du code en java. un nom d'attribut ou de méthode commence par une minuscule. Les autres caractèrs sont en minuscules sauf ceux qui débutent un nouveau mot : factureNumero1 par exemple. Le nom des classes fonctionne de la même manière, mais commence par une majuscule : class FactureClient.
Lorsque l'on passe un objet en paramètre d'une méthode, le passage se fait pas référence alors que dans le cas des variables des types primitifs, les
paramètres sont passés par valeur. Soit une fonction d'une classe GestionClient accorderUneRemise(Client clt,double taux); et soient les instructions :
public class GestionClient{ public static void main(String[] args) { GestionClient objetGestionClient=new GestionClient(); double taux=0.075; Client clt=new Client("c:\\Clients\\client57.txt"); objGestionClient.accorderUneRemise(clt,taux); System.out.println("La remise accordee pour le client "+clt.remiseAccordee); System.out.println("le taux "+taux); } public void accorderUneRemise(Client clt,double taux) { clt.remiseAccordee=taux; taux=0; } }
La remise accordee pour le client 0.075 le taux 0.075
String ch1,ch2; ch1="Bonjour"; ch2="Bonsoir";La notation ch1="Bonjour" vaut création d'un nouvel objet de type String qui est réferencée ensuite par ch1. Ce type de notation qui diffère des notations habituelles vues plus haut est assez rare en Java. Pour l'affichage des flux en sortie, on utilise les fonctions de la variable de classe out de la classe System : println(String) et print String. C'est ce que l'on faisait de manière implicite et sans le savoir plus haut en écrivant :
int u=25; System.out.println("Valeur de la variable u : "+u);La classe String contient une méthode length() qui permet d'obtenir la longueur d'une chaîne.
String ch1="Le langage"; String ch2="Java"; String ch=ch1+ch2;La concaténation de deux String vaut création d'un nouvelle objet de type String.
int u=25; System.out.println("Valeur de la variable u : "+u);Dans ce cas, la variable u donne lieu à la création d'une String avant concaténation.
Facture fact1=new Facture(5,6.3); System.out.println("La facture fact1 donne en affichage : "+fact1+" quelle interprétation peut-on en donner ?");Pour des raisons qui seront explicitées aux chapitres 4 et 5, si l'utilisateur a défini une méthode String toString() dans sa classe, alors c'est la chaîne renvoyée par cette fonction qui sera concaténée pour l'affichage, sinon c'est une chaîne qui donne l'adresse en mémoire vive qui est renvoyée.
String str="Bonjour"; String str2="Bonsoir"; String str3="Bonsoir"; System.out.println(str.equals(str2));//Affiche false System.out.println(str2.equals(str3));//Affiche true System.out.println(str3.equals(str2));//Affiche true System.out.println(str3.equals("bonsoir"));//Affiche falseVoici évoquée une première classe de l'API : nous n'avons pas donné l'ensemble des méthodes ou des attributs de la classe String, de la même manière que nous ne donnerons pas l'ensemble des méthodes et des attributs de toutes les classes de l'API, en revanche, on peut faire réference au site de sun qui reproduit via ses pages l'ensemble de cette hiérarchie, et notamment pour la classe String : Classe String sur le site de sun
Dans une méthode non static, il y a différents types de variables :
public class A{ public static void main(String[] args) { A varA=new A(); varA.att1=6; varA.methode1(5.0,6); } public int att1; public void methode1(double att1,int a1) { System.out.println(att1); } }Dans ce cas, c'est la variable locale qui est utilisée par le programme qui affiche "5.0", pour manipuler l'attribut de l'objet : this.att1. Si att1 était un attribut de classe, on utilisera A.att1 pour manipuler l'attribut de classe.