java:memoire
Différences
Ci-dessous, les différences entre deux révisions de la page.
| Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente | ||
| java:memoire [2013/11/04 10:26] – [Les types pointeurs] bruno | java:memoire [2025/11/18 14:04] (Version actuelle) – [Les types "pointeurs"] bruno | ||
|---|---|---|---|
| Ligne 270: | Ligne 270: | ||
| </ | </ | ||
| - | Java se contente de mettre sa table de correspondance à jour, et ne crée par un nouvel espace mémoire: effectivement, | + | Java se contente de mettre sa table de correspondance à jour, et ne crée pas un nouvel espace mémoire: effectivement, |
| **Ce type d' | **Ce type d' | ||
| Ligne 293: | Ligne 293: | ||
| Si j' | Si j' | ||
| - | ==== La mémoire des pointeurs | + | La figure suivante représente cette affectation dans la mémoire. |
| + | {{ : | ||
| + | Seul le premier octet de l' | ||
| + | |||
| + | ==== La mémoire | ||
| + | |||
| + | Vous avez appris qu'un tableau en java ne peut pas changer de taille: il faut lui indiquer combien d' | ||
| + | |||
| + | <code java> | ||
| + | //tableau de 3 entiers | ||
| + | int[] tabInt = new int[3]; | ||
| + | |||
| + | //tableau de 4 Object | ||
| + | Object[] tabObject = new Object[4]; | ||
| + | |||
| + | </ | ||
| + | |||
| + | Pourquoi donc? | ||
| + | |||
| + | Hé bien c'est facile à comprendre. Java va mémoriser la taille du tableau, et pour chaque case va réserver une zone mémoire qui contiendra une adresse vers la donnée. | ||
| + | |||
| + | Les adresses sont en général codées avec 4 octets. Un tableau de 20 éléments aura donc une taille de 20*4 = 80 octets, **quel que soit le type de données qu'il contient**. | ||
| + | Si vous essayez de lire une donnée en dehors de la plage déclarée (par exemple // | ||
| + | |||
| + | Java génère dans ce cas une erreur de type // | ||
| + | |||
| + | Voici quelques exemples illustrés/ | ||
| + | |||
| + | === Tableau de types primitifs | ||
| + | |||
| + | En mémoire, chaque case du tableau " | ||
| + | |||
| + | L' | ||
| + | |||
| + | La **zone pointée** fait la taille du type primitif (2 octets pour un short, 4 pour un int, etc.). | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | === Tableau de dimension 2, 3, n... === | ||
| + | |||
| + | Soit le code suivant: | ||
| + | <code java> | ||
| + | short [][] tab = new tab[6][4]; | ||
| + | </ | ||
| + | |||
| + | //tab// est un tableau de dimension 6 qui contient des tableaux de dimension 4. | ||
| + | |||
| + | Nous avons vu qu'un tableau est identifié par son adresse en mémoire. | ||
| + | |||
| + | Donc, chacune des 6 cases du tableau //tab// va contenir l' | ||
| + | Chaque tableau de dimension 4 contiendra l' | ||
| + | |||
| + | On devrait donc parler d'un tableau de 6 adresses de tableaux de 4 adresses de short. | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | |||
| ==== Construction d' | ==== Construction d' | ||
| + | Nous avons vu que pour qu'il y ait création, il faut nécessairement que **new** soit utilisé. | ||
| + | |||
| + | Mais que fait cet opérateur **new**? | ||
| + | |||
| + | **new** attend en paramètre un **constructeur** (pas un nom de classe!!!). | ||
| + | |||
| + | Prenons par exemple la hiérarchie de classes suivante: | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | Voici le code des classes Animal et Pingouin: | ||
| + | |||
| + | <code java Animal.java> | ||
| + | /** | ||
| + | Une toute petite classe représentant un Animal | ||
| + | | ||
| + | */ | ||
| + | public class Animal{ | ||
| + | /**le nom de l' | ||
| + | private String nom =""; | ||
| + | /** l' | ||
| + | private String espece=""; | ||
| + | |||
| + | /** | ||
| + | Constructeur d' | ||
| + | @param n valeur pour nom | ||
| + | @param e valeur pour espece | ||
| + | */ | ||
| + | public Animal(String n, String e){ | ||
| + | nom = n; | ||
| + | espece = e; | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | Constructeur d' | ||
| + | L' | ||
| + | @param n valeur pour nom | ||
| + | */ | ||
| + | public Animal(String n){ | ||
| + | nom = n; | ||
| + | espece = " | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | Pour faire jouer l' | ||
| + | Affiche un petit message en console. | ||
| + | */ | ||
| + | public void jouer(){ | ||
| + | System.out.println(" | ||
| + | } | ||
| + | |||
| + | } | ||
| + | </ | ||
| + | |||
| + | et Pingouin: | ||
| + | |||
| + | <code java Pingouin.java> | ||
| + | /** Une toute petite classe pour représenter un Pingouin*/ | ||
| + | public class Pingouin extends Animal{ | ||
| + | |||
| + | /** | ||
| + | Constructeur de Pingouin, qui affecte automatiquement la chaîne " | ||
| + | Utilise le constructeur d' | ||
| + | @param n le nom du pingouin | ||
| + | */ | ||
| + | public Pingouin(String n){ | ||
| + | super(n," | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | Ce qui est bien quand on est Pingouin, c'est qu'on peut glisser sur le ventre | ||
| + | */ | ||
| + | public void glisser(){ | ||
| + | System.out.println(" | ||
| + | } | ||
| + | |||
| + | } | ||
| + | </ | ||
| + | |||
| + | De quels constructeurs disposons-nous? | ||
| + | |||
| + | Classe Object: // | ||
| + | |||
| + | Classe Animal: // | ||
| + | |||
| + | Classe Pingouin: // | ||
| + | |||
| + | Pour construire (créer) un //Object// (une instance d'// | ||
| + | <code java> | ||
| + | Object o1 = new Object(); | ||
| + | Object o2 = new Animal(" | ||
| + | Object o3 = new Animal(" | ||
| + | Object o4 = new Pingouin(" | ||
| + | </ | ||
| + | |||
| + | J'ai utilisé 4 fois l' | ||
| + | |||
| + | Parmi ces instances: | ||
| + | * //o1// pointe vers une instance de type //Object// | ||
| + | * //o2// et //o3// pointent chacune vers une instance de type //Animal// | ||
| + | * //o4// pointe vers une instance de type // | ||
| + | |||
| + | Mais est-ce que pour autant j'ai la même chose en mémoire? | ||
| + | |||
| + | **NON!** | ||
| + | |||
| + | Regardons ce qui se passe en détail. | ||
| + | |||
| + | <code java> | ||
| + | Object o1 = new Object(); | ||
| + | </ | ||
| + | |||
| + | Java va créer une zone de mémoire pour les attributs de //o1//, une autre pour ses méthodes (qui sont celles de la classe Object). | ||
| + | |||
| + | Les attributs (caractéristiques) de chaque instance d' | ||
| + | |||
| + | On peut schématiser cette opération de la manière suivante: | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | <code java> | ||
| + | Object o1 = new Object(); | ||
| + | Object o2 = new Animal(" | ||
| + | </ | ||
| + | |||
| + | Cette fois-ci, on utilise le constructeur de Animal. Un Animal **est un** Object, donc java va commencer par construire un Object en appelant le constructeur // | ||
| + | |||
| + | Ensuite, il va ajouter les attributs de l' | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | <code java> | ||
| + | Object o1 = new Object(); | ||
| + | Object o2 = new Animal(" | ||
| + | Object o3 = new Animal(" | ||
| + | </ | ||
| + | |||
| + | On utilise maintenant le constructeur // | ||
| + | Il n'y a pas de différence avec le cas précédent. Notez cependant que la zone mémoire contenant les méthodes de Animal n'est pas dupliquée (les méthodes/ | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | <code java> | ||
| + | Object o1 = new Object(); | ||
| + | Object o2 = new Animal(" | ||
| + | Object o3 = new Animal(" | ||
| + | Object o4 = new Pingouin(" | ||
| + | </ | ||
| + | |||
| + | Cette fois-ci, le constructeur // | ||
| + | |||
| + | Il suffit alors de " | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | Vous vous rappelez du " | ||
| + | |||
| + | C'est le processus de java qui s' | ||
| + | |||
| + | La dernière figure vous permettra de bien comprendre comment il fonctionne: tant qu'une zone de la mémoire reçoit une flèche, ça veut dire qu' | ||
| + | |||
| + | Une zone de mémoire qui ne reçoit plus de flèche est une zone dont les données ne pourront jamais être récupérées: | ||
| + | |||
| + | |||
| + | ==== Et les tableaux d' | ||
| + | |||
| + | Que se passe-t-il dans le cas de tableaux d' | ||
| + | |||
| + | Réfléchissez, | ||
| + | |||
| + | ===== Java l' | ||
| + | |||
| + | Et pour finir, parlons des pertes de mémoires de java! Je veux parler du problème suivant: | ||
| + | |||
| + | <code java> | ||
| + | Object o1 = new Object(); | ||
| + | Object o2 = new Animal(" | ||
| + | Object o3 = new Animal(" | ||
| + | Object o4 = new Pingouin(" | ||
| + | |||
| + | o4.jouer(); | ||
| + | |||
| + | o4.glisser(); | ||
| + | </ | ||
| + | |||
| + | Le compilateur java nous indique deux erreurs: | ||
| + | |||
| + | < | ||
| + | TypeConstruit.java: | ||
| + | o4.jouer(); | ||
| + | ^ | ||
| + | symbol: | ||
| + | location: variable o4 of type Object | ||
| + | TypeConstruit.java: | ||
| + | o4.glisser(); | ||
| + | ^ | ||
| + | symbol: | ||
| + | location: variable o4 of type Object | ||
| + | 2 errors | ||
| + | |||
| + | </ | ||
| + | |||
| + | Pourtant, //o4// a été construit avec un constructeur de // | ||
| + | |||
| + | Rappelez-vous que javac n'est qu'un programme, pas toujours très intelligent donc! | ||
| + | |||
| + | Ce que javac voit, c'est que //o4// est déclaré comme //Object//. | ||
| + | |||
| + | Il cherche donc les méthodes //jouer()// et // | ||
| + | |||
| + | Pourtant, si on regarde le dernier schéma, on voit bien que ces méthodes sont chargées dans la mémoire! | ||
| + | |||
| + | Il va donc falloir explicitement dire à Java de regarder un peu plus en détail. C'est le fameux **cast** ou **transtypage** que nous avons déjà vu avec les types primitifs, sauf que là il ne peut y avoir perte de données: soit l' | ||
| + | |||
| + | Nous allons donc définir une variable et lui dire de pointer dans la même zone mémoire que //o4//, en demandant à java d' | ||
| + | |||
| + | <code java> | ||
| + | Object o4 = new Pingouin(" | ||
| + | /* ça marche pas! | ||
| + | o4.jouer(); | ||
| + | o4.glisser(); | ||
| + | |||
| + | Animal a = (Animal)o4; | ||
| + | a.jouer(); | ||
| + | |||
| + | ((Pingouin)o4).glisser(); | ||
| + | </ | ||
| + | |||
| + | Je vous ai mis deux manières de faire: | ||
| + | * dans le premier cas, je déclare une variable //a//, et après j' | ||
| + | * dans le deuxième cas, je fais directement le cast sans passer par une variable: java créera une variable temporaire et appellera ensuite la méthode glisser(). | ||
| + | |||
| + | Et la question de la fin pour voir si vous avez bien compris: | ||
| + | |||
| + | // | ||
| + | |||
| + | ===== Codes complet des exemples ===== | ||
| + | |||
| + | Archive du code au format tar.gz : {{: | ||
| + | |||
| + | Vous pouvez exporter ce TP en pdf en utilisant le lien du menu de gestion de cette page (le dernier, petite icône en crayon) | ||
java/memoire.1383560767.txt.gz · Dernière modification : 2013/11/04 10:26 de bruno