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 perd 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 n'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 ....
Commentaires
Amusant que vous parliez de ça maintenant, j'ai justement utilisé il y a peu un PasswordField et m'étonnait de devoir passer par un char[].
Cette histoire d'immuabilité m'intrigue. Ça voudrait dire que toutes les valeurs successives de n'importe quelle String sont stockées, mais que la String ne pointe que sur la plus récente ? Bonjour le gaspillage de mémoire dans ce cas.
Et j'en vois pas non plus l'utilité, puisque si on veut re-prendre une valeur qu'on a déjà eu, j'imagine qu'en la réassignant on créera probablement un doublon plutôt que de pointer à nouveau sur la valeur déjà en RAM. Il doit y avoir autre chose... Faudra que j'aille fouiner les docs du web.
Quant à l'utilité du char[] versus le String, je vois pas non plus.
Immutable veut dire que les strings (constants) sont stockés en RAM et que si tu déclares
s = "Foo";
s = "Bar";
s = "Foo";
La troisième affectation va récupérer en RAM le premier string (qui aura été conservé) ... voilà pourquoi on utilise char[] qui n'est pas immutable.
Tu as tout en main pour faire le test et vérifier que je ne me trompe pas ;-)