Amphi I 1
Eléments de Java
• Comment manipuler une variable ?
• Types primitifs en Java
• Références
• Structures dynamiques
Amphi I 2
Comment manipuler une variable ?
• Deux techniques possibles
- On utilise directement la valeur de la variable
- On utilise l’adresse (ou référence) où la variable est rangée dans la mémoire.
243
Adresse variable
Les types primitifs en JAVA
• Le type booléen
boolean true ou false (1 bit)
• Le type caractère
char caractère Unicode (2 octets)
• Les types entier
byte (1 octet ) [-128, 127]
short (2 octets) [-32768, 32767]
int (4 octets) [-2147483648, 2147483647]
long (8 octets) [-9.1018 , 9.1018]
• Les types réel
float (4 octets) simple précision double (8 octets) double précision
Autres types déjà rencontrés
• Tableau
• Chaîne de caractères
• Objets
class Personne {
String nom;
int age;
}
String nom = "Lundi";
int[] valeurs;
float[] T = new float[10];
Amphi I 5
Une règle simple, mais fondamentale
En Java, les variables de type
primitif (booléen, caractère, entier ou réel) sont manipulées par
valeur. Les variables de type non primitif sont manipulées par
référence.
Amphi I 6
Pour s'en convaincre
public static void main(String[] args) {
byte[] T = {5, 2, 6};
System.out.println("Tableau " + T);
}
Que va afficher le programme à l'éxécution ?
La réponse
public static void main(String[] args) {
byte[] T = {5, 2, 6};
System.out.println("Tableau " + T);
}
> Tableau [B@f96da1 [ --> Tableau
B --> d'octets (bytes)
@ --> Adresse, suivi de l'adresse en hexadécimal
Manipulation d'un tableau
Le tableau est manipulé par sa référence, qui
indique l'endroit où le début du tableau est stocké en mémoire.
T[1]
T[2]
T[0]
case f96da1 case f96da2 case f96da3
Amphi I 9
Conséquences (1)
• Une variable de type tableau contient une adresse
• Représentation graphique
5 2 6 T •
0 1 2
Amphi I 10
Que fait ce programme ?
public static void main(String[] args) {
byte[] S = {5, 2, 6};
byte[] T;
T = S;
System.out.println("Tableau " + S +
" " + T);
}
Que fait ce programme ?
> Tableau [B@f665ab [B@f665ab
Les variables S et T désignent la même adresse !
public static void main(String[] args) {byte[] S = {5, 2, 6};
byte[] T;
T = S;
System.out.println("Tableau " + S +
" " + T);
}
• Avant l'instruction T = S;
indéfini
• Après l'instruction T = S;
Graphiquement ...
5 2 6 S •
T •
0 1 2
5 2 6 S •
T •
5 2 6 S •
T •
0 1 2
Amphi I 13
Conséquences (2)
public static void main(String[] args) {
byte[] S = {5, 2, 6};
byte[] T = S;
T[1] = 8;
System.out.println(S[1]);
}
Amphi I 14
Conséquences (2)
public static void main(String[] args) {
byte[] S = {5, 2, 6};
byte[] T = S;
T[1] = 8;
System.out.println(S[1]);
}
> 8
Les variables S et T désignent la même adresse...
• Avant l'instruction T[1] = 8;
• Après l'instruction T[1] = 8;
Graphiquement ...
5 2 6 S •
T •
5 8 6 S •
T •
0 1 2 5 2 6 S •
T •
5 2 6 S •
T •
0 1 2
Conséquences (3)
public static void main(String[] args) {
byte[] S = {5, 2, 6};
byte[] T = new byte[3];
for (byte i = 0; i < S.length; i++) T[i] = S[i];
System.out.println(S + " " + T);
System.out.println(T == S);
}
Amphi I 17
Conséquences (3)
public static void main(String[] args) {
byte[] S = {5, 2, 6};
byte[] T = new byte[3];
for (byte i = 0; i < S.length; i++) T[i] = S[i];
System.out.println(S + " " + T);
System.out.println(T == S);
}
> [B@d16b31 [B@d16b34
> false (Deux adresses distinctes ! )
Amphi I 18
• Avant la boucle for
• Après la boucle for
Graphiquement ...
5 2 6 S •
T •
0 1 2
5 2 6 S •
T
•
0 1 2 5 2 6
•
Structures (1) Une "personne" a
– un nom (une chaîne de caractères) – un age (un entier)
class Personne {
String nom;
int age;
}
Les champs de la structure "personne" sont "nom" et
"age".
Structures (2)
public static void main(String[] args) {
Personne p = new Personne();
p.nom = "Dominique";
p.age = 22;
System.out.println(p.nom + ", "
+ p.age + " ans");
}
Dominique p • 22
nom age
>Dominique, 22 ans
•
Amphi I 21
public static void main(String[]args) {
Personne p = new Personne();
p.nom = "Dominique";
p.age = 22;
System.out.println(p);
}
>Personne@a14cad
Le contenu de la variable p est une référence
Structures (3)
Amphi I 22
public static void main(String[] args) {
Personne p = null;
System.out.println(p);
}
La référence null
Note : ni p.nom ni p.age ne sont définis.
null est une référence spéciale: c'est la valeur par défaut de toute variable de type non primitif.
>null
public static void main(String[] args) {
Personne p = new Personne();
System.out.println(p + " nom: "
+ p.nom + " age: " + p.age);
}
L'opérateur new
>Personne@9def2d nom: null age: 0
L'opérateur new initialise les champs de la structure à leur valeur par défaut (null pour une chaîne de caractères, et 0 pour un entier)
Synthèse sur les références
• Le contenu d’une variable de type non primitif est appelée une référence.
• Il existe une référence spéciale, nommée null.
• Une référence (sauf la référence null) est typée (exemples: classe ou tableau).
• L’opérateur new crée un nouvel objet de la classe, et
retourne la référence à cet objet.
Amphi I 25
Tableau de structures Création similaire aux autres tableaux :
Comme les éléments du tableau sont de type non primitif, ils sont initialisés à null.
Affectation:
Personne p = new Personne();
p.nom = "Dominique";
p.age = 22;
T[0] = p;
Personne[] T = new Personne[3];
Amphi I 26
Graphiquement...
p •
Personne p = new Personne();
p.nom = "Dominique";
p.age = 22;
T[1] = p;
T •
0 1 2
•
Dominique 22
nom age
•
Un exercice
Quel est le résultat de ce programme ?
Personne[] T = new Personne[3];Personne p = new Personne();
p.nom = "Dominique" ; p.age = 22;
T[1] = p;
System.out.println("Tableau: " + T);
for (int i = 0; i < T.length; i++) System.out.print(" " + T[i]);
Un exercice
Quel est le résultat de ce programme ?
Personne[] T = new Personne[3];Personne p = new Personne();
p.nom = "Dominique" ; p.age = 22;
T[1] = p;
System.out.println("Tableau: " + T);
for (int i = 0; i < T.length; i++) System.out.print(" " + T[i]);
>Tableau: [LPersonne;@9ce743
> null Personne@9ce748 null
Amphi I 29
Suite de l'exercice Quel est le résultat de ce programme ?
Personne[] T = new Personne[3];
Personne p = new Personne();
p.nom = "Dominique" ; p.age = 22;
T[1] = p;
System.out.println(T[1].age);
Personne q = T[1];
q.age = 24;
System.out.println(T[1].age);
Amphi I 30
Suite de l'exercice Quel est le résultat de ce programme ?
Personne[] T = new Personne[3];
Personne p = new Personne();
p.nom = "Dominique" ; p.age = 22;
T[1] = p;
System.out.println(T[1].age);
Personne q = T[1];
q.age = 24;
System.out.println(T[1].age);
>22
>24
Après q = T[1], p, q et T[1] désignent la même référence.
Les classes en JAVA
• Une classe est un bloc de base d'un programme Java. Elle définit un type non primitif et contient
•
des variables
• des méthodes
• du code d'initialisation
• d'autres classes
• Un objet est une instance d’une classe.
• Un constructeur d'une classe est une méthode, de même nom que la classe, sans type de retour.
Constructeurs Les constructeurs servent à créer des objets. Ils sont appelés par new.
class Personne {
String nom;
int age;
Personne(String s, int k) {
nom = s;
age = k;
} }
Personne p = new Personne("Luc", 22);
Amphi I 33
Constructeurs (2)
On peut avoir plusieurs constructeurs de même nom (celui de la classe), qui diffèrent par le nombre ou le type de leurs arguments.
Personne p = new Personne("Luc", 22);
Personne q = new Personne("Anne");
class Personne { ...
Personne(String s, int k) { nom = s;
age = k;
}
Personne(String s) { nom = s;
} }
Amphi I 34
Utilisation
public static void main(String[] args) {
Personne p = new Personne("Luc",22);
Personne q = new Personne("Anne");
System.out.println(q.nom + ", "
+ q.age + " ans");
}
>Anne, 0 ans
q.age a été initialisé à sa valeur par défaut (0 pour un entier)
Constructeur par défaut
public static void main(String[] args) {
Personne p = new Personne();
}
Si aucun constructeur n'a été défini, Java utilise un constructeur par défaut, sans argument.
Piège ! Le constructeur par défaut n'est plus défini si un autre constructeur a été défini.
Plan
• Comment manipuler une variable ?
• Types primitifs en Java
• Références
• Structures dynamiques
Amphi I 37
Structures de données dynamiques (1)
• Le problème
Les structures de données en algorithmique sont souvent complexes et de taille variable
• Limitations des tableaux – Taille fixe
– Structure fixe (linéaire) – Manque de souplesse – Peu économe en mémoire
Amphi I 38
Structures de données dynamiques (2)
• Critères de sélection
– Gestion économe de la mémoire – Conception aussi simple que possible
• Solution
– Allocation de la mémoire au fur et à mesure des besoins – Définition récursive des structures
– Manipulation reposant sur un petit nombre d'opérateurs
• Exemples
– Listes, piles, files d’attente
– Arbres (arbres binaires de recherche) – Graphes (plan du métro, réseau)
Listes chaînées Une liste chaînée est une suite de couples formés d'un élément et de l'adresse (référence) vers l’élément
suivant. C'est un jeu de piste (ou un lien dans une page).
Opérations usuelles sur les listes
– Créer une liste vide et tester si une liste est vide.
– Afficher une liste
– Ajouter un élément en tête de liste.
– Rechercher un élément.
– Supprimer un élément.
– Afficher, retourner, concaténer, dupliquer . . .
Listes chaînées en Java
class Liste { int contenu;
Liste suivant;
Liste(int x,Liste a) { contenu = x;
suivant = a;
} }
• • •
...contenusuivant contenusuivant contenusuivant
¥
Amphi I 41
Liste vide
static Liste faireListeVide() {
return null;
}
static boolean estVide(Liste a) {
return (a == null);
}
Amphi I 42
Ajouter un élément en tête de liste
static Liste ajouter(int x, Liste a) {
return new Liste(x, a);
}
• •
...a
•
x•
¥
Initialisation d'une liste (1)
// Liste vide Liste a = null;
// constructeur
Liste a = new Liste(2, null);
a
•
2a // Liste vide
Liste a = faireListeVide();
¥
¥
Initialisation d'une liste (2)
Liste a = new Liste(0, null);
Liste b = new Liste(2, a);
•
2•
b
•
0a
// Liste des entiers de 1 à n Liste a = null;
for (int i = n; i >= 1; --i) a = ajouter(i, a);
•
1•
2•
... na
Ruse !
¥
¥
Amphi I 45
Affichage d'une liste (itératif)
static void afficherI(Liste a) {
while (a != null)!
{
System.out.print(a.contenu + " ");
a = a.suivant;
}
System.out.println();
}
8
•
2•
5•
1•
5>8 2 5 1 5
•
¥ aAmphi I 46
Affichage d'une liste (récursif)
static void afficher(Liste a) {
if (estVide(a))
System.out.println();
else {
System.out.print(a.contenu + " ");
afficher(a.suivant);
} }
Que se passe-t-il si les deux dernières instructions sont interverties ?
Longueur d'une liste (récursive)
static int longueur(Liste a) {
if (a == null) return 0;
return 1 + longueur(a.suivant);
}
Note. On s'est dispensé du else, car la présence du
return le rend inutile. On peut très bien le laisserpour rendre le programme plus lisible.
Longueur d'une liste (itérative)
static int longueurI(Liste a) {
int longueur = 0;
while (a != null) {
++longueur;
a = a.suivant;
}
return longueur;
}