2. Une première classe

2.1. Écriture d'une classe

Nous reverrons en détails les mécanismes de création de classe. Voyons ici un exemple simple qui nous permettra d’introduire les concepts généraux. Nous allons écrire une classe Marin, capable de modéliser des marins. Pour le moment, cette classe va rester simple : un marin possède un nom et un prénom, deux chaînes de caractères, ainsi qu'un salaire, entier. Écrivons cette classe de la façon la plus simple possible, nous verrons dans la suite qu'elle comporte des erreurs de conception, mais cela reste un premier exemple accessible.

Exemple 2. Une première version de la classe Marin

public  class Marin {  
   String nom, prenom ;
    int salaire ;
	
    public Marin (String nouveauNom, String nouveauPrenom,  int nouveauSalaire) {  
        nom = nouveauNom ;   
        prenom = nouveauPrenom ;   
        salaire = nouveauSalaire ;   
    }
    
     public Marin (String nouveauNom,  int nouveauSalaire) {  
        nom = nouveauNom ;   
        prenom =  "" ;   
        salaire = nouveauSalaire ;   
    }
    
     public  void augmenteSalaire (int montant) {  
        salaire = salaire + montant ;   
    }	 
}

On reconnaît la structure classique d'une classe :
  • le nom de la classe : public class Marin
  • les champs : nom et prenom de type String, et salaire de type int
  • deux éléments nouveaux : des méthodes, public Marin (il y en a deux), et public void augmenteSalaire.
La méthode public void augmenteSalaire est une méthode classique. Le mot-clé public signifie qu’elle peut être appelée en dehors de la classe. L’identificateur void indique que cette méthode ne renvoie rien. Le mot augmenteSalaire est le nom de la méthode. Suit une parenthèse qui désigne les arguments que l’on doit passer à cette méthode, un entier de type int dans ce cas. Le nom d’une méthode et les paramètres qu’elle reçoit constituent ici la signature d’une méthode. Deux méthodes sont différentes si leurs signatures sont différentes. Elles peuvent donc avoir le même nom, à condition qu'elles diffèrent par les paramètres qu’il faut leur passer, et qu'elles aient même type de retour. Nous verrons d'autres contraintes sur les méthodes dans la suite. Les deux premières méthodes public Marin sont d'un type particulier : elles ne possèdent pas de type de retour. Ces méthodes sont les constructeurs de la classe Marin. Nous verrons en détails la fonction des constructeurs en Java, et leur fonctionnement interne, disons pour le moment que pour obtenir un objet instance d'une classe, il faut appeler explicitement l'un de ses constructeurs (ici nous en avons écrit deux), avec les bons paramètres. Un constructeur est une méthode qui doit respecter quelques contraintes :
  • elle doit porter le même nom que la classe ;
  • ne pas avoir de déclaration de type de retour (pas même void),
  • notons ici qu'un constructeur n'est pas nécessairement public.
Dans notre exemple, nous avons écrit deux constructeurs différents, qui ne prennent pas les mêmes arguments en entrée, et diffèrent donc par leur signature. Ces deux définitions sont légales, et peuvent cohabiter dans une même classe. Enfin, remarquons que Java fait la distinction entre les majuscules et les minuscules.

2.2. Instanciation de cette classe

On peut créer un objet instance de cette classe par une déclaration du type :
 Marin marin1 = new Marin ("Surcouf", "Robert", 25000) ;
L’utilisation de new réserve un espace mémoire capable de contenir un objet de type Marin, et l'initialise. Nous reverrons en détail en quoi consiste cette initialisation, disons pour le moment qu'il s'agit de mettre à 0 le contenu de cet espace mémoire. Un appel est ensuite fait au constructeur qui a pour signature Marin (String, String, int). Cet espace mémoire est enfin référencé par marin1. Créons un autre objet de type Marin de cette façon :
 Marin marin2 = marin1 ;
Lorsque l’on utilise une affectation d’objet, la machine Java recopie la référence vers l’objet cible dans la variable de destination. Donc l’objet marin2 référence la même zone mémoire que marin1. Il n’y a pas, dans les opérateurs d’affectation d’objet, de duplication de la zone mémoire. Les deux objets marin1 et marin2 sont donc les mêmes. Testons cela sur quelques exemples simples. Augmentons le salaire de marin1 par appel de la méthode augmenteSalaire(int) :
 marin1.augmenteSalaire(100) ;
Le salaire de marin2 est aussi augmenté, puisqu’il s’agit physiquement du même objet. Programmons la commande :
 marin1.nom = marin1.nom.toUpperCase() ;
On convertit de ce fait le champ nom de marin1 en majuscule. Comme marin2 partage ce champ avec marin1, marin2.nom est aussi en majuscules. Comparons marin1 et marin2 :
 boolean b1 = (marin1 == marin2) ;
Lorsqu'il agit sur des objets, l'opérateur d'égalité == compare les valeurs des références, et non pas leur contenu. Si les deux références marin1 et marin2 référencent la même zone mémoire (en C on aurait parlé de pointeurs, et d'adresses), alors elles sont égales. Dans ce cas, la valeur de b1 est true. Instancions maintenant marin1 et marin2 de la façon suivante :
 Marin marin1 = new Marin ("Surcouf", "Robert", 25000) ;
 Marin marin2 = new Marin ("Surcouf", "Robert", 25000) ;
Cette fois-ci, dans la mesure où chaque variable porte une référence vers une zone mémoire qui lui est propre (deux opérations new sont réalisées), changer un champ de marin1 n'aura pas d'effet sur marin2. Comparons marin1 et marin2 de la même façon que précédemment :
boolean b2 = (marin1 == marin2) ;
La valeur de b2 est dans ce cas false, puisque les deux objets marin1 et marin2 sont logés dans deux zones mémoire différentes.
Java langage & API
Retour au blog Java le soir
Cours & Tutoriaux
Table des matières
Introduction : un peu d'histoire
1. Java : genèse d'un nouveau langage
Programmer en Java
1. Un premier exemple
1.1. Aperçu général, cycle de vie
1.2. Un premier programme
1.3. Programmes, applets, servlets, etc...
2. Une première classe
2.1. Écriture d'une classe
2.2. Instanciation de cette classe
3. Types de base, classes et objets
3.1. Types de base
3.2. Classes et objets
Classes Object et String
1. Introduction
2. La classe Object
2.1. La méthode toString()
2.2. La méthode clone()
2.3. La méthode equals()
2.4. La méthode hashCode()
2.5. La méthode finalize()
2.6. La méthode getClass()
3. La classe String
3.1. Introduction
3.2. Construction d'un objet de type String
3.3. Concaténation, StringBuffer et StringBuilder
3.4. Concaténations de chaînes de caractères depuis Java 8
3.5. Concaténations de chaînes de caractères depuis Java 11
3.6. Extraction d'une sous-chaîne de caractères
3.7. Comparaison de deux chaînes de caractères
3.8. Méthodes de comparaisons lexicographiques
3.9. Méthode de recherche de caractères
3.10. Méthode de modification de chaîne
3.11. Méthode de duplication
3.12. Support de l'unicode, internationalisation
Structure d'une classe
1. Introduction
2. Classes
2.1. Classes publiques
2.2. Classes internes
2.3. Classe membre
2.4. Classes locales
2.5. Classes anonymes
2.6. Le mot-clé this
3. Éléments statiques
3.1. Champ statique
3.2. Cas des constantes
3.3. Bloc statique
3.4. Classe membre statique
4. Membres d'une classe, visibilité
4.1. Bloc non statique
4.2. Accès à un membre, visibilité
4.3. Les champs
4.4. Signature d'une méthode
4.5. Les méthodes
4.6. Getters et Setters
5. Constructeur, instanciation
5.1. Chargement d'une classe
5.2. Constructeurs d'une classe
5.3. Instanciation d'un objet
5.4. Destruction d'objets
5.5. Le mot-clé final
6. Énumérations
6.1. Déclaration d'une énumération
6.2. Classe énumération
6.3. Méthode toString()
6.4. Méthode valueOf()
6.5. Méthode values()
6.6. Méthode ordinal()
6.7. Méthode compareTo()
6.8. Constructeurs privés
6.9. Classe utilitaire : EnumSet
Noms, opérateurs, tableaux
1. Introduction
2. Identificateurs, noms et expressions
2.1. Identificateurs et noms
2.2. Expressions
3. Opérateurs, ordre d'exécution
3.1. Ordre d'exécution
3.2. Les opérateurs
3.3. Les opérateurs ++ et --
3.4. Les opérateurs % et /
3.5. Les opérateurs <<, >> et >>>
3.6. L'opérateur instanceof
3.7. Les opérateurs &, | et ^
3.8. Les opérateurs && et ||
3.9. L'opérateur ? ... :
3.10. Les opérateurs d'affectation
4. Tableaux
4.1. Création d'un tableau
4.2. Initialisation d'un tableau
4.3. Utilisation d'un tableau comme un Object
4.4. Tableaux de tableaux
4.5. Copie de tableaux
5. Blocs, boucles et contrôles
5.1. Blocs
5.2. Mots-clés réservés
5.3. Tests : if et switch
5.4. Boucles : for, while, do ... while
5.5. Commandes continue et break
5.6. Commandes return et goto
Nombres, précision, calculs
1. Introduction
2. Calculs
2.1. Précision
2.2. Codage des nombres flottants
2.3. Le mot-clé strictfp
2.4. Conversion de types
3. Dépassements de capacité
3.1. Cas des entiers
3.2. Cas des flottants
3.3. Bibliothèques BigInteger et BigDecimal
4. Fonctions mathématiques
4.1. Fonctions usuelles
4.2. Générateurs aléatoires
5. Classes enveloppe
5.1. Associer les types de base à des objets
5.2. Auto-boxing
Héritage, abstraction, interfaces
1. Introduction
2. Abstraction et encapsulation
2.1. Abstraction
2.2. Encapsulation
3. Héritage
3.1. Définition de l'héritage
3.2. Conséquences pour les membres
3.3. Polymorphisme
3.4. Empêcher l'héritage
4. Classes abstraites
5. Interfaces
5.1. Introduction
5.2. Définition
5.3. Java 8 et les interfaces
5.4. Utilisation des interfaces
5.5. Définition de constantes dans les interfaces
5.6. Utilité des interfaces
Packages
1. Introduction
2. Notion de paquet
2.1. Déclaration d’appartenance à un paquet
2.2. Chargement d’une classe
2.3. Choix de nom
3. Archives, chemin de recherche, classpath
3.1. Archives
3.2. Variable CLASSPATH
3.3. Notion de classloader
3.4. Bilan sur les classes chargées
3.5. Visibilité
3.6. Conseils d'écriture, bibliothèque standard
Exceptions
1. Introduction
2. Erreurs et Exceptions
2.1. Classe Throwable, notion de stack trace
2.2. Classe Error
2.3. Classe RuntimException
2.4. Classe Exception
3. Déclenchement d'une exception
3.1. Exceptions déclenchées par la JVM
3.2. Exceptions déclenchées par l'application
4. Capter une exception
4.1. Traiter une exception localement
4.2. Code de captage
5. Créer ses propres exceptions
Entrées / sorties
1. Introduction
2. Notion de fichier
2.1. Introduction
2.2. La classe File
2.3. Construction d'une instance de File
2.4. Méthodes exposées
3. Flux de sortie
3.1. Introduction, notion de flux
3.2. Écriture de caractères, classe Writer
3.3. Bufferisation, construction d'un flux sur un autre
3.4. Utilisation de PrintWriter
3.5. Écriture d'octets, OuputStream
3.6. Écriture de types primitifs : DataOutputStream
3.7. Écriture d'objets : ObjectOutputStream
4. Flux d'entrée
4.1. Introduction
4.2. Lecture de caractères, classe Reader
4.3. Bufferisation, lecture ligne par ligne
4.4. Lecture d'octets : InputStream
4.5. Lecture de types primitifs : DataInputStream
4.6. Lecture d'objets : ObjectInputStream
5. Lecture et écriture de flux croisés
5.1. Introduction
5.2. Lire des caractères sur un flux binaire : classe InputStreamReader
5.3. Écrire des caractères sur un flux binaire : classe OutputStreamWriter
5.4. Remarque sur les jeux de caractères
6. Serialization d'objets
6.1. Enjeu de la sérialization d'objets
6.2. Serialization d'un objet
6.3. Sérialization d'une grappe d'objets
6.4. Première surcharge : méthode writeObject() readObject()
6.5. Deuxième surcharge : utilisation d'un externalizer
6.6. Troisième surcharge : utilisation d'un objet proxy
7. Flux compressés
7.1. Introduction
7.2. Flux de type gzip
7.3. Flux de type zip