Chaîne de caractères littérales et objet String

Les spécifications de Java expliquent que les chaînes de caractères littérales sont une suite vide ou de plusieurs caractères entre guillemets. Ceci correspond donc au type String. Par conséquent le langage Java permet de créer des chaînes de caractères de deux manières différentes :

// Initialisation de la chaîne de caractères
// par la construction de l'objet String
String foo = new String("Hello World foo");
 
// Initialisation de le chaîne de caractères
// par affectation d'une chaîne de caractères littérale
String bar = "Hello World bar";

On peut se demander si le compilation de ce code donne le même code intermédiaire (bytecode) ou pas.

Le compilation du code pour la construction de l’objet String donne le bytecode suivant :

// Nouvel objet String et référence de cette objet sur la pile
NEW java/lang/String
 
// Duplique la référence sur le haut de la pile
DUP
 
// Pousse "Hello World foo" depuis le pool de
// constantes des Strings sur la pile
LDC "Hello World foo"
 
// Invoque la méthode d'initialisation pour construire la String
// avec la référence de l'objet et la chaîne de caractères
INVOKESPECIAL java/lang/String.(Ljava/lang/String;)V
 
// Stocke la référence de l'objet String
// depuis la pile dans une variable locale
ASTORE 1

C’est le code intermédiaire normal pour la création d’un objet de type String.

La compilation de l’initialisation d’une chaîne de caractères littérales donne une autre suite d’instructions à ma grande surprise :

// Pousse "Hello World foo" depuis le pool de
// constantes des Strings sur la pile
LDC "Hello World bar"
 
// Stocke la référence de "Hello World foo"
// depuis la pile dans une variable locale
ASTORE 1

La grosse différence est que l’initialisation ne passe pas par la construction d’un objet String mais se contente de copier une référence de la chaîne de caractères dans une variable locale ! Du coup, cela économise le temps de construction d’un type String et trois instructions.

Qu’en est il des performances ?

Le test de performance est fait sur la [CONFIG_ARM926EJ-S] avec JamVM 1.5.4 / GnuClasspath 0.98 / Java 1.3. Le code de test permet d’initialiser en boucle les chaînes de caractères suivant les deux méthodes.

Nombre d'appelString foo = new String("foo")String bar = "bar"
16ms1ms
1011ms7ms
5046ms19ms
10048ms35ms

Les tests confirment que l’initialisation d’un objet String via son constructeur est moins performante qu’avec une chaîne de caractères littérales. Suivant les projets et les contraintes de l’embarqué, cela peut améliorer les performances de votre application.

Laisser un commentaire