Cours 5 : Mémoire et fil d'exécution
Programmation impérative en java
Le livre de cuisine
Mais on gère ceci avec une pile...
Java
C'est un langage de programamtion (i.e syntaxe et sémantique).
C'est une machine virtuelle, pour des raisons de portabilité (ex: applets). Fichiers .class et .java
C'est un environnement avec des choses prêtes à l'emploi
Squelette d'application
import java.lang.*;

class MonProgramme {

    public static void main(String[] args) {
C'est ici que l'on tape un programme, i.e. le fil commence par la zone main
    }
}
      
Variables et affectation
Définition d'une variable
Il s'agit d'un symbole désignant une zone mémoire. L'adresse de la zone est appelé la left-value, le contenu de la zone la right-value. En java, il faut déclarer les variables avant de les utiliser. La mémoire que l'on nomme en déclarant une variable est prise sur le sommet de la pile. La déclaration à la forme suivante :
type nom;
Exemples:
int i;
String toto;
Types natifs
Le nom du type est en minuscules. Exemples de déclarations:
int i;
float j;
long k;
boolean is_valid;
char c;
Il y a une ambiguïté de nommage, que l'on voit quand on positionne le contenu de la mémoire à une certaine valeur. C'est ce qu'on appelle l'affectation.
int i;
int j;

i = 5;
j = 3;
i = j+8;
j = j+1;  // le j à gauche du = n'est pas le même que celui à droite ! (contenu vs contenant).
Les pointeurs
Il s'agit de variables dont les valeurs sont des adresses, i.e de cases mémoires dont le contenu est l'adresse d'autres cases. Les adresses stockés désignent une zone mémoire qui n'est pas la pile, que l'on appelle le tas. Les pointeurs sont utilisés pour de la mémoire correspndant aux types à champs nommés et aux tableaux, que nous allons voir. La mémoire se réserve, i.e. s'alloue via un mot-clé new.
Types à champs nommés (accessibles par pointeurs)
Un complexe, c'est l'agglomération de deux réels, l'un s'appelant re et l'autre im. C'est ce que l'on décrira dans le fichier Complex.java suivant:
class Complex {
  public float re; // un champ de type float, appelé "re".
  public float im; // un champ de type float, appelé "im".
}
Dans le squelette, on peut alors écrire:
Complex a; // pointeur a sur la pile
Complex b; // pointeur b sur la pile

a = new Complex();   // Allocation dans le tas de deux floats.
a.re = 3;            // le premier vaut maintenant 3.
a.im = 5;            // le deuxième vaut maintenant 5.
a.im = a.im + 1;     // les champs sont des variables... mais dans le tas.

b.re = 3.14;         // Erreur...
b = new Complex();   // Allocation d'UN AUTRE agglomérat de 2 floats.
b.re = 3.14;         // Là, b.re désigne effectivement de la mémoire.
b.im = a.re;

b = a;               // Affectation DES POINTEURS !!!!
La mémoire allouée lors du deuxième new est perdue car inaccessible par des noms. C'est ce qu'on appelle une fuite de mémoire (memory leak), mais Java fait le ménage tout seul via le garbage collector.
Tableaux (accessibles par pointeurs)
L'idée des tableaux est d'avoir des noms de champs calculables.... puisque ce sont des entiers ! Exemple:
float[] t;            // allocation d'un pointeur dans la pile.
float[] tt;           // allocation d'un pointeur dans le tas.
int j;

t = new float[5];     // Agglomérat de 5 floats alloué dans le tas.
j = t.length;         // j vaut 5 !
t[0] = 34.7;
t[1] = 3.9;
t[2] = t[1]+t[0];
t[3] = 0;
t[4] = 5;
t[5] = 5;             // Erreur de dépassement d'indice !

j = j - 2;
t[j] = 50;            // Le nom t[j] est défini à l'exécution.

tt = new float[200];
tt = t;               // Les 200 cases sont perdues.