Les références

Types de références en Java

Ce site ne sera plus alimenté de contenu après août 2014. Tous les nouveaux articles seront redigés pour www.waitingforcode.com

En PHP on ne doit pas considérer les problématiques liées à des références. On initialise une variable et on ne doit pas gérer son placement dans la mémoire. En Java la gestion des références est plus complexe car elle prend en compte de différents types de références.

Qu'est-ce que c'est qu'une référence en Java ?

Pour bien comprendre la spécificité du Java, il faut commencer par définir une référence. Avec la construction de chaque objet, il est placé dans un endroit dans la mémoire. Cependant, le développeur ne peut pas y accéder directement. Par contre, il peut le faire via une sorte d'indicateurs qui sont les références placées dans des variables. Elles permettent donc de récupérer les objets directement depuis la mémoire.

Les références ne sont pas représentées sous leurs formes réelles (il n'y aura pas une chaîne de caractères pour un String, ni un entier pour un Integer). A la place on retrouve des identifiants qui pointent vers un endroit précis de la mémoire. Ces identifiants sont uniques.

Si une variable appelée ne possède pas de référence correspondante (elle est null), une exception NullPointerException est captée.

Comment une référence est placée dans la mémoire ?

Chaque fois, avant d'allouer de l'espace dans la mémoire à un objet, la machine virtuelle du Java vérifie combien d'espace libre elle dispose. Si ce nombre est insuffisant, elle fait appel au Garbage Collector de Java pour faire un peu de nettoyage.

Regardons donc ce processus sur deux exemples : un type primitif (int) et un objet :

afficher le code

Voici le résultat :

0 Map reference is : {2=B, 1=A} Map after operation : {2=B, 1=A} String after operation : AB

On voit clairement que même en passant un paramètre Map m, on manipule réellement l'objet private Map map. On opère sur le même objet via une variable différente. Ni copie supplémentaire, ni nouvelle instance de cette classe ne sont pas mises dans la mémoire. On opère sur le même objet copié intégralement dans une autre variable. Pareil pour le cas du text qui est l'instance de la classe StringBuffer.

Par contre, ce n'est pas le cas pour int i où l'on a l'impression de récupérer uniquement une valeur et de modifier toute une autre variable j. Alors une copie de la valeur i et réalisée avant l'appel de la méthode qui la manipule.

Cependant, dans les deux cas il s'agit du mode de transmission appelé pass-by-value. Il repose sur le principe qu'on manipule des valeurs. Regardons pourquoi cela s'applique également au passage des références en paramètres. Pour le constater, on rajoute ceci dans la méthode mapOperation() :

    m = new HashMap();
    m.put("new-"+key, "new-"+value);
    System.out.println("Value of new map reference is : " + m);

Voici le résultat :

0 Map reference is : {2=B, 1=A} Value of new map reference is : {new-2=new-B} Map after operation : {2=B, 1=A} String after operation : AB

On constate que les Maps sont deux objets différents. Autrement dit, ils possèdent deux adresses en mémoire distinctes. La déclaration m = new HashMap(); crée donc un nouvel objet dans la mémoire, référencée avec une variable m. Il ecrasse également toutes les modifications effectuées au sein de cette méthode sur la Map privée.

Types de références

Java distingue 4 types de références :

1. strong (forte) : signifie les références qui ne sont collectées par le Garbage Collector que lorsque leurs objets deviennent null (cela veut dire que les objets ne sont plus utilisés par l'application et qu'ils peuvent être supprimés). Un bon exemple des références fortes sont des éléments des collections. Tant qu'une collection est référencée (différente de null), elle et ses composants sont considérées comme des références fortes.

2. soft (douce) : illustre les références qui peuvent être réclamées par le Garbage Collector. Cependant ce dernier ne va pas essayer de le faire. Par contre, si la machine virtuelle de Java décide de récupérer plus d'espace, elle va automatiquement nettoyer la mémoire des références douces. La libération pourra être lieu pour des objets des références douces qui n'ont pas des références fortes.

3. weak (faible) : il s'agit des références faibles qui n'essaient même pas de se protéger contre la collecte du Garbage Collector. La collecte pourra avoir lieu si aucune référence forte et douce n'existe pour l'objet en question.

4. phantom (phantôme) : les méthodes get() de cette référence renvoient toujours null. Elle est rajoutée dans la queue de références correspondante dès lors que l'objet est supprimé de la mémoire. Elle devient libérable quand l'objet y attaché n'a aucune référence forte, douc et faible. Une référence phantôme permet une action de notification avant la libération.

Cette référence peut être utile dans les opérations qui utilisent beaucoup de ressource. On peut imaginer la situation où l'on traite un grand fichier texte dans la mémoire. Un autre est en attente de traitement. Pour éviter des exceptions du type OutOfMemory, on peut commencer à manipuler l'autre fichier après la suppression du premier de la mémoire.

Regardons les exemples de ces références :

afficher le code

Voici le résultat :

Weak reference WeakHashMap with not null object weak value WeakHashMap with null object null Phantom reference Found reference java.lang.ref.PhantomReference@9304b1. Looking for java.lang.ref.PhantomReference@9304b1 java.lang.ref.PhantomReference@9304b1 matches java.lang.ref.PhantomReference@9304b1

En occurence on n'a pas pu voir la libération de la référence douce car elle est stocké jusqu'à la saturation de la mémoire.

télécharger les fichiers d'exemple
Bartosz KONIECZNY Informations sur le langage

Une question ? Une remarque ?

*

*

Un conseil PHP

Comment ne pas afficher une partie de la page ?

En PHP, grâce aux méthodes liées aux tampons de sortie on peut librement manipuler les éléments qu'on veut afficher sur la page. La fonction ob_end_clean() permet de ne pas afficher le contenu défini avant son appel. Prenons un exemple :

echo 'test page';
ob_end_clean();
echo 'test 2 page';
Ce bout de code affichera uniquement le deuxième echo ("test 2 page"). Le premier sera ignoré et "supprimé" par la fonction ob_end_clean().