Remise à niveau en programmation objets en Java

Mise en place

Pour ces séances, nous allons utiliser l'IDE IntelliJ. Suivez les étapes ci-dessous

  • Lancer IntelliJ.
  • Si un projet est ouvert par défaut, fermez-le (menu File).
  • Choisir l'option New Project :
    • Renseigner le nom (RAN).
    • Laisser la Location inchangée.
    • Choisir IntelliJ pour le build system.
    • Le JDK doit être le 22 (Java en version 22 installée sur nos postes).
    • Activer l'option Add sample code.
    • Désactiver l'option Generate code with onboarding tips
  • Créer le projet.
  • Vous devriez vous trouver face au code ci-dessous
    public class Main {
        public static void main(String[] args) {
            System.out.println("Hello world!");
        }
    }
    
  • Cliquer sur la flèche verte en face de public static void main(...) pour lancer l'exécution.
  • Main est appelée une classe et main (en minuscules) est appelée une méthode. Les méthodes sont composées d'instructions et de déclarations de variables. Dans les exemples ci-dessous nous allons enrichir la méthode main.

Les bases de la programmation java

Variables et types

En java, la déclaration s'opère de la manière suivante (l'affectation et la valeur de droite sont optionnelles) :

int age = 25;
float size= 181.0f;
Travail à faire : Intégrer ces déclarations dans main et réaliser les affichages de ces deux variables.
Travail à faire : Faire d'autres essais avec les types de bases long, short, boolean, double et char (les constantes caractères sont notées 'C'). Lire cette documentation.

Simplifier les déclarations. Très souvent le compilateur peut déduire le type à partir de la partie droite de l'affectation. Dans ce cas, le type de gauche peut être remplacé par le mot-clé var.

var size = 181.0f;

Dans cet exemple, on ne sait pas si 181.0 est un float ou un double. Nous pouvons ajouter un d ou un f à la fin de la constante 181.0 afin de préciser. Un L peut être ajouté à une constante entière afin de préciser que c'est un long.

Note : Le nommage des identificateurs (classe, méthode et variable) doit se faire de préférence en anglais et la séparation entre les mots doit être signifiée par un changement de la casse : productShortName. Il ne faut par utiliser product_short_name.

Variable constante. Une variable peut ne pas changer de valeur lors de l'exécution (son nom améliore la lisibilité du code). Dans ce cas, il est conseillé de déclarer cette variable comme non modifiable en utlisant final avant le type. Il est également conseillé de nommer cette variable avec des majuscules et le caractère _ pour séparer les mots.

Travail à faire : Utiliser final pour certaines variables.
Travail à faire : Utiliser la méthode print à la place de println. Passer ensuite à printf (avec cette documentation).
Travail à faire : Utiliser Ctrl-Alt-L pour formatter de manière automatique votre code.

Les opérations

Lire cette documentation afin de découvrir les opérations

Travail à faire : Effectuer les calculs dans main et afficher le résultat.

Les tableaux

Lire cette documentation jusqu'à la section 7 et tester les exemples proposés.

Travail à faire : Essayer une matrice d'entiers avec le code ci-dessous.
int[][] matrix = new int[3][5];

Les tests

Lire cette documentation afin de découvrir les tests.

Travail à faire : Avec des tests, changer l'affichage en fonction de la valeur de certaines variables.

La boucle while

Lire cette documentation afin de découvrir la boucle while.

Travail à faire : Prendre l'heure courante (System.currentTimeMillis() un long) et chercher le par dichotomie entre 0 et le plus grand long possible. Combien faut-il d'itérations ?

La boucle do while

La boucle do ... while permet d'exécuter au moins une fois le corps de boucle :

do {
    ...
} while (condition_de_continuation)
Travail à faire : Utiliser cette structure pour améliorer la recherche dichotomique.
Travail à faire : Explorer cette documentation.

La boucle for

La boucle for permet de regrouper les trois parties principales :

for(initialisation; condition_de_continuation; incrémentation) {
    ...
}
Travail à faire : Utiliser cette structure pour refaire la recherche dichotomique.
Travail à faire : Utiliser la clause break pour sortir de l'itération. Utiliser ensuite la clause continue pour revenir à la condition de continuation.

La clause switch

Lire cette cette documentation et programmer certains exemples.

La programmation objet en Java

Classe et variables d'instance

Nous avons utilisé des variables qui semblent définir une personne. Une classe permet de regrouper des informations en vu de représenter une entité. Dans votre projet (menu File), créer la classe Person ci-dessous :

public class Person {
    public int age = 25;
    public float size = 181.0f;
}

age et size sont appelées des variables d'instance. Pour les utiliser, vous devez au prélable créer (dans la méthode main) une instance de la classe Person (aussi appelé objet) dont la référence est stockée dans une variable de type Person (var est utilisable). La notation pointée (voir ci-dessous) est utilisée pour accèder aux variables d'instance à partir d'une référence.

...
Person p = new Person();
p.age = 35;
System.out.println(p.size);
System.out.println(p.age);
...
Note : La clause public est importante car elle indique que les variables d'instance sont accessibles en dehors de la classe.
Travail à faire : Créer deux personnes, changer les caractéristiques de ces personnes et afficher ces informations.
Travail à faire : Enrichir cette classe avec d'autres informations.

Méthode

En java nous pouvons ajouter à une classe des fonctions qui opérent sur les variables d'instance. Nous les appelerons des méthodes (ou méthodes d'instance).

public class Person {
    ...

    public void printPerson() {
        System.out.printf("%f cm, %d ans\n", size, age);
    }
}

L'utilisation est très simple via la notation pointée et s'applique aux références :

...
Person p = new Person();
p.age = 35;
p.printPerson();
p = null; /// Je n'ai plus besoin de cette instance
...
Note : La clause void utilisée dans la méthode printPerson indique que cette méthode ne renvoie aucune valeur.
Travail à faire : Intégrer ce code à votre projet et tester le bon fonctionnement.
Note : Le nom printPerson n'est pas très judicieux et pourrait être remplacé par print puisque la méthode s'applique à une personne.
Travail à faire : Modifier le nom de la méthode en utilisant la fonction Refactor de votre IDE (sélectionner l'identificateur et utiliser le menu contextuel).
Note : Dans une méthode, la variable this est une référence vers l'instance sur laquelle s'applique la méthode.
Travail à faire : Utiliser this dans la méthode print.
Travail à faire : Créer deux méthodes privées (clause private) spécialisées dans l'affichage de l'age et du nom. Modifier ensuite print afin d'utiliser ces deux méthodes privées. Vérifier que l'utilisation de this est optionnelle.

Argument d'une méthode et valeur de retour

Ajouter la méthode ci-dessous :

public void setSize(float newSize) {
    size = newSize;
}
Travail à faire : Utiliser cette méthode pour changer la taille et vérifier sa bonne prise en compte. Utiliser le même principe pour l'age. Nous appellerons ces méthodes des setters.
Travail à faire : Définir également les méthodes getXxx qui renvoient la valeur de la variable d'instance Xxx. Nous les appellerons des getters.
Travail à faire : Définir une méthode grow qui va prendre deux arguments : le nombre d'années ainsi que le nombre de centimètres à ajouter. Utiliser cette méthode. Ajouter ensuite deux nouvelles versions de grow qui travaillent uniquement sur une information. Nous pouvons donc définir plusieurs méthodes de même nom à condition que les arguments (nombre et types) puissent les différencier.

Variables de classe

Avec la clause static il est possible de définir une variable de classe qui existe de manière unique au niveau de la classe sans liaison avec les éventuelles instances (objets) créées.

public class Person {
    public static int counter = 0;
    ...
}

L'accès à ces variables de classe passe par le nom de la classe :

...
Person.counter++;
System.out.println(Person.counter);
...

Dans cet exemple, la variable de classe représente le nombre de personnes créées.

Travail à faire : Chercher un autre exemple de variable de classe.

Méthode de classe

Les méthodes de classe (aussi appelées méthodes statiques) offrent des actions associées à une classe mais pas aux instances. Ces méthodes n'ont pas accès aux variables d'instances.

public static void incrementCounter() {
    counter++;
}

public static int getCounter() {
    return counter;
}
Travail à faire : Utiliser ces méthodes pour modifier le compteur et l'afficher.
Note : L'utilisation de ces méthodes est délicate et doit être aussi limitée que possible.

Constructeur

Un constructeur est une méthode qui porte le nom de la classe et qui ne renvoie aucune valeur. Il est appelé au moment de l'instanciation de la classe.

public Person() {
}

public Person(int newAge, float newSize) {
    age = newAge;
    size = newSize;
}
Travail à faire : Modifier le constructeur sans argument afin qu'il affecte les valeurs par défaut. Un constructeur peut appeler un autre constructeur avec la syntaxe this(...arguments...).
Note : En Java, il n'y a pas de destructeur. Il n'y a pas non plus de libération d'une instance. Les instances inutilisées sont détectées automatiquement par un algorithme de récupération mémoire. Il faut néanmoins veiller à supprimer toutes les références que nous jugeons inutiles en effectuant une affectation à null (p = null).

Les packages

A ce stade nous avons deux classes. Afin de les ranger convenablement, nous allons créer un package. Suivez les étapes ci-dessous :

  • Sélectionner le répertoire source.
  • Avec le menu contextuel, créer un package (par exemple fr.univamu.ran).
  • Faire glisser les deux classes dans ce package.
  • Observer la clause package ajoutée au début de vos classes.
Note : Les packages sont destinés à enrichir le nom des classes afin d'éviter les conflits. Traditionnellement, une classe d'un projet Sugiton, rédigée par l'université d'Aix-Marseille, devrait être placée dans le package fr.univamu.sugiton car AMU a déposé le nom univ-amu.fr et cela garantit l'absence de conflit. Rien n'empêche de créer des sous-packages dans sugiton.

Les chaînes de caractères

En java, les chaînes de caractères sont des instances de la classe String (y compris les "constantes").

Travail à faire : Ajouter à la classe Person une variable d'instance name de type String ainsi que les méthodes getter et setter. Modifier les constructeurs en conséquence. Adapter la méthode print.
Travail à faire : La construction d'une chaîne complexe par concaténation est coûteuse. Consulter la documentation de StringBuffer et utiliser cette classe pour construire une chaîne intéressante (avec des caractères, des entiers, des flottants). Remarque : utiliser le mécanisme de complétion de votre IDE : une fois que vous avez tapé le "." utiliser le Ctrl-Espace pour choisir la méthode disponible.