tete du loic

 Loïc YON [KIUX]

  • Enseignant-chercheur
  • Référent Formation Continue
  • Responsable des contrats pros ingénieur
  • Référent entrepreneuriat
  • Responsable de la filière F2 ingénieur
  • Secouriste Sauveteur du Travail
mail
loic.yon@isima.fr
phone
(+33 / 0) 4 73 40 50 42
location_on
ISIMA
  • twitter
  • linkedin
  • viadeo

local_cafe Prems local_cafe

Date de première publication : 2024/08/28

La première séance est une séance d'introduction au langage avec :

Bonjour monde !!

Préalable

Il existe différentes versions de Java, les versions Long Term Support (8, 11, 17 et 21 - la prochaine doit sortir en 2025) et les versions intermédiaires, plus fréquentes (la derniere version en date est la 22 sortie en mars 2024 et la prochaine, la 23, sort le 17 septembre)...

Pour pouvoir travailler, il faut vérifier que vous avez un environnement correctement installé, on peut vérifier cela en tapant en ligne de commande les instructions suivantes :

$ javac -version
$ java -version

Vous devez avoir des versions compatibles et s'il vous manque javac il faudra installer un JDK Standard Edition.

Les debians de l'ISIMA embarquent la LTS 17.0.6 d'openJDK.

La documentation des classes prédéfinies est consultable en ligne. Il faut juste choisir la bonne version et placez celle-ci dans vos favoris de navigation :

Le dernier lien est un tutoriel qui explique pas mal de choses sur Java et l'objet. Seul bémol, il est resté en version 8.

Premier programme

Créez le fichier texte suivant (l'extension est importante) :

$ code prems.java

et mettez le code suivant :


/* ma première classe */
public class Exemple1 {

    public static void main(String[] argv) {
       // afficher un message
       System.out.println("Bonjour les ZZ2 !");
    }
}

Vous l'avez compris, l'idée est de créer une classe Exemple avec un méthode main() qui affiche un petit bonjour sur la console !

Le langage Java n'est pas un langage de script. Le fichier n'est donc pas directement "interprétable" comme python ou bash. Pour compiler, il faut taper :

javac prems.java

Vous avez votre première erreur de compilation java ! Le fichier doit obligatoirement porter le nom de la classe

javac Exemple1.java

Cette fois, il n'y a plus d'erreur, jetez donc un coup d'œil à votre répertoire. Un nouveau fichier apparaît d'extension .class. Vous pouvez essayer d'exécuter ce fichier :

$ ls
$ ./Exemple1.class

Vous avez besoin d'un deuxième programme pour exécuter du code Java. Il faut faire appel à la machine virtuelle Java (JVM) :

java Exemple1

Vous pouvez réaliser les choses suivantes :

Manipulation de variable de type non objet

On crée un nouveau fichier/classe pour manipuler une variable non objet de type int :


public class Exemple2 {

    public static void main(String[] argv) {
        int i = 0;
        
        i  = i + 1;
        i += 1;
        i *= 2;

        System.out.println(i);
        System.out.println(++i);
        System.out.println(i);
        System.out.println(i++);
        System.out.println(i);

        i = (int) 10.6;
        System.out.println(i);

        i = 50;
        while (i>0) {
          System.out.println(i);
          i %=2;
        }

        for(int j = 3; j <10 ; j+=2)
          System.out.println(j);

        // if (!i)
        // System.out.println("i est nulle");

    }
}

Vous pouvez constater que la manipulation d'une variable entière est très similaire à celle du C. Il y a un petite différence que vous allez rencontrer lorsque vous décommenterez les deux dernières lignes.

En Java, il y a un type boolean pour gérer les valeurs booléennes true ou false. Il faut donc écrire explicitement les tests pour que cela marche.

Manipulation d'objets de classes prédéfinies

StringBuffer

Il y a plus de 4400 classes prédéfinies en Java. Pour découvrir le langage, on va s'intéresser à l'une d'entre elles : StringBuffer . Cette classe permet de manipuler une chaîne de caractères modifiable.

Exécutez le code suivant :


public class Exemple3 {

    public static void main(String[] argv) {
        StringBuffer s1 = new StringBuffer("Bonjour");

        System.out.println(s1.toString());
        System.out.println(s1.length());
        System.out.println(s1.capacity());

        s1.append(" les ZZ");
        s1.append(2);

        System.out.println(s1.toString());
        System.out.println(s1.length());
        System.out.println(s1.capacity());

        StringBuffer s2 = s1;

        s2.append("!");
        System.out.println(s1.toString());
        System.out.println(s1);  // Alors ?
        
        // s2 = new StringBuffer("plus rien à voir");
        // System.out.println(s1);
        // System.out.println(s2);

       // inverser et afficher la chaine s1
    }
}

La ligne 4 est complexe car elle fait trois opérations distinctes :

La ligne 6 permet d'afficher l'objet référencé par s1 sur la sortie standard. On verra plus tard ce qui se passe exactement.

length(),capacity() et append() sont des méthodes que l'on peut appeler sur l'objet référencé par s1. Les méthodes sont appelées grâce à l'opérateur .

Ainsi s1.length() renvoie le nombre de caractères utilisés de l'objet référencé par s1

La ligne 17 crée un alias pour l'ojet référencé par s1. Cela permettra de manipuler le même objet par un nom ou par un autre. La ligne 20 permet de vérifier que c'est bien le cas.

Il ne vous reste plus qu'à décommenter la fin du code pour voir ce qui se passe.

Trouvez maintenant dans la documentation officielle comment inverser la chaîne de caractères s1 et affichez-là !

Référence non utilisée

On vient de voir qu'en Java, on ne manipule pas d'objet directement mais qu'on le fait grâce à une référence. La référence n'est pas toujours associée à un objet en mémoire, il y a donc une valeur spéciale pour cela : null. Modifiez le début du programme précédent comme suit :


public class Exemple3 {

  public static void main(String[] argv) {
      StringBuffer s1 = null;
      
      System.out.println(s1.toString());
      s1 = new StringBuffer("Bonjour");
      System.out.println(s1);
      // ...

  }
}

Ce code génère toutefois une erreur à l'exécution car, à l'instar des pointeurs, on ne peut appeler une méthode sur une référence nulle : s1.toString() n'a pas de sens. On obtient alors l'équivalent d'un segmentation fault cher au C

Corrigez l'erreur en testant la valeur de la référence pour éviter l'appel si cette référence est nulle.


if (s1 != null) System.out.println(s1.toString());

La référence en tant que variable locale doit toujours être initialisée. Dans le cas contraire, cela ne compilera pas.

Enlevez l'initialisation à la ligne 4 pour voir ce que cela fait : StringBuffer s1;

Une référence peut être mise à null à tout moment. Cela signifie simplement que l'on n'a plus besoin de l'objet anciennement référencé

String

La classe String est très utilisée car elle permet de manipuler des chaines de caractères mais celles-ci ne sont plus modifiables après leur création. Ne cherchez pas les méthodes pour les modifer, ce n'est pas possible.

Vérifions tout cela :


public class Exemple4 {
  public static void main(String[] argv) {
    String s1 = new String("essai");
    System.out.println(s1.concat(" de concatenation"));
    System.out.println(s1);

    String s2 = new String("essai");
    System.out.println(s2.replace('s', 'Z'));
    System.out.println(s2);

    // s2 = new String("changement valide");
    // System.out.println(s2);
  }
}

Les lignes 6 et 10 montrent respectivement que les chaines référencées par s1 et s2 ne sont pas modifées et que les lignes précédentes ont généré des "copies".

Décommentez les lignes 12 et 13. À votre avis, pourquoi ces lignes sont-elles valides ? Que se passe-t-il réellement ?

L'objet pointé par s2 est bien immuable une fois qu'il est créé mais s2 n'est pas un objet, donc s2 est modifiable

Création de votre première classe

Vous allez créer (par étapes) et instancier votre première classe "maison" dont le diagramme UML est le suivant :

Joueur
- nom : chaine
- score : entier
- actif : booléen
- compteur : entier
+ constructeur(s)
+ afficher()
+ les getters
+ les setters
+ getCompteur() : entier

class Joueur {
  int score;
}

public class Exemple5 {
    public static void main(String[] argv) {
      // instanciation d'un joueur
    }
}

Les attributs ont des valeurs par défaut quand les objets sont instanciés en JAVA (les variables locales ne sont pas initialisées par défaut)

Encapsulation

Mettre les attributs en privé et écrire les getters et les setters, si c'est pertinent, permet de respecter le principe d'encapsulation.

Il est un peu pénible d'écrire de répéter les appels aux différents attributs.

Constructeur

On va maintenant initialiser les attributs à la construction de l'objet en dotant la classe d'un constructeur.

Le code ne compile plus. En effet, main() fait appel à un constructeur qui n'existe pas ou plutot n'existe plus. Le compilateur Java fournit un constructeur sans argument par défaut si celui-ci n'est pas fourni. Ce n'est plus le cas dès qu'un constructeur - quel qu'il soit - est fourni. Si on en a également besoin, il faut le fournir.

Vous avez probablement dupliqué l'initialisation de l'attribut dans les différents constructeurs. Nous allons maintenant éviter celle-ci en utilisant le fait qu'un constructeur puisse en appeler un autre.

Si l'appel est fait correctement, il n'y a pas de deuxième instanciation. C'est une facilité de syntaxe.


  class Joueur {
    // constructeur sans argument
    public Joueur() {
      this("noname");  // appel du constructeur avec paramètre
                       // l'appel doit être la premiere instruction du constructeur
    }

    // constructeur qui fait le boulot
    public Joueur(String nom) {
       // ... travail à faire
    }
  }

Attribut de classe

Nous allons maintenant nous intéresser à un attribut classique : il s'agit de mémoriser le nombre de joueurs instanciés.

Un attribut de classe peut être utilisé dans une méthode classique ou dans une méthode de classe. Un attribut classique ne peut être utilisé dans une méthode de classe.