notes·de·pit

Parfois j'apprends à pêcher à des gens qui n'aiment pas le poisson

getText versus getPassword

Je lis dans la documentation de l’API java que getText sur un JPasswordFiled est deprecated. En effet, getText retourne un string et getPassword est préféré car il retourne un char[].

Un étudiant me faisait la remarque qu’il préférait quand même utiliser getText car ça l’embête de manipuler le char[] ! Après avoir coupé la tête dudit étudiant, j’explique ici à sa dépouille le pourquoi d’une telle approche.

Les String en Java son immuables (immutable).

In the Java programming language, unlike C, an array of char is not a String,and neither a String nor an array of char is terminated by ‘\u0000’ (the NUL character). A String object is immutable, that is, its contents never change, while an array of char has mutable elements. The method toCharArray in class String returns an array of characters containing the same character sequence as a String. The class StringBuffer implements useful methods on mutable arrays of characters.

Source: Java Langage Specifications (p294, ou 328 du PDF)

Ce qui veut dire que si je sauve une variable de type String dans mon code, il est plus que probable que sa valeur reste en RAM même après si je perds la référence vers ce string. Je m’explique.

String s = "AAAAAAAA";

La chaine “AAAAAAA” se trouve quelque par en RAM, ça ne me surprend pas, on peut dire que ça me rassure même.

String s = "AAAAAAA"; 
s = "BBBBBBB";

Je pourrais m’attendre à ce que la chaine “AAAAAAAA” ne se trouve plus en RAM puisque j’ai changé sa valeur. Mais puisque les string sont immuables en java, il n’en est rien, la chaine est toujours en RAM.

Pour vérifier ceci, j’utilise deux programmes. Le premier, jmap, fourni avec mon JDK me permets d’obtenir un dump de la mémoire d’un processus. Une instruction de cette forme fait l’affaire;

jmap -dump:live,format=b,file=file.dump <pid>

Le second, hexdump, me permet de visualiser (en fait placer le contenu dans un fichier et l’éditer avec vi afin de me faciliter les recherches) le contenu de ce fichier “dump”… il me reste à chercher les chaines de caractères qui m’intéressent.

hexdump -C file.dump > file.hexdump

J’écris un petit programme Java simple tel que;

import java.util.Scanner ; 

public class StringCharArray { 

  private static Scanner clavier = new Scanner ( System.in ) ;  

    public static void main ( String\[\] args ) { 
      String s = "Password chaine 1"; 
      s = "Password chaine 222";
      char\[\] chars = 
        { 'P', 'A', 'S', 'S', 'W', 'O', 'R', 'D'};
      System.gc();
      chars = new char\[\] 
        { 'p', 'p', 'a', 'a', 's', 's', 'w', 'w', 'd', 'd'};
      clavier.next(); // wait
    }
}

Si ce que je pense est correct, je m’attend à trouver les chaines : Password chaine 1, Password chaine 222 et ppaasswwoorrdd mais pas PASSWORD. Voici les screenshots que j’obtiens.

Screenshot

Screenshot

Screenshot

Screenshot

Ok, j’ai raison 1, mais c’est peut-être un coup de bol.

Je pourrais/devrais m’arrêter là mais pour être complet, je veux tester effectivement avec un GUI et un JPasswordField. J’écris un code permettant d’afficher ceci

Screenshot

…et là, c’est moins concluant. J’entre les mêmes valeurs que dans le premier exemple et je fais passer le garbage collector. Le premier string disparait, ainsi que le premier char[] mais pas le deuxième string ni le deuxième char[].

J’en conclus que le garbage collector n’est pas passé. Par contre je devrais voir le premier string… sinon je ne comprend pas l’utilité d’utiliser char[] dans ce cas.

Je suis preneur de toutes idées…

un jour plus tard

Dire qu’un string est immuable veut dire que je ne peux pas le modifier 2. On n’imagine pas écrire du code comme ceci :

String s = "un string";
// s[0] = 'T'; // compile pas : immuable
// s.charAt(0) = 'T'; // compile pas : immuable

Par contre je peux le faire avec un char[]. J’en conclus donc et c’est important que : l’utilisation de getPAssword ne peut aller de paire qu’avec une mise à 0 des caractères après utilisation comme induit sur le site d’oracle . Du genre;

char[] password =  jPasswordFiled.getPassword();
// vérification de la validité de ce mot de passe
Arrays.fill(password, 0);

Voilà qui est clair maintenant….


  1. Merci à mon collègue Nicolas pour le rappel de l’immuabilité des strings 

  2. Remerci à Nicolas qui est au taquet