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.
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
- la première zone est un
JTextFiled
, - la seconde un
JPasswordFields
, - le bouton “Get fields” permet d’associer les valeurs à des variables tandis que
- le bouton “Garbage” repositionne ces variables à null et appelle le garbage collector
…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….