Le Touilleur Express

  • Accueil
  • A propos de l’auteur
  • A propos du Touilleur Express
Next Previous

String et intern() on ne sait pas tout sur les Strings

12 septembre, 2006

Hier soir, plongé dans du code de Xerces-J pour notre parseur XML j’ai vu plusieurs fois ce bout de code:


protected final static String A_CONSTANT = "constantTest".intern();

Quel est le fonctionnement de la méthode intern() de la class String ? Comme vous le savez en Java, il y a deux moyens de comparer deux objets. La méthode equals() et l’opérateur ==. La méthode equals() s’assure que les deux objets contiennent les mêmes données alors que l’opérateur == vérifie si les références de l’ojbet pointent sur le même objet. D’ailleurs une des premières leçons des débutants en Java est qu’il faut en général utiliser la méthode equals() pour comparer 2 String en Java.
En effet à votre avis quel est le résultat de l’exécution de ce code ?


System.out.println("Comparaison: "+ new String("Touilleur)==new String("Touilleur") );

Si vous avez répondu Comparaison: true vous vous êtes trompé. S’agissant de deux objets distints, ils ne sont pas égaux. Le code retourne false. Voyons maintenant avec l’opérateur equals de la class String:


System.out.println("Comparaison: "+ new String("Touilleur).equals(new String("Touilleur")) );

Dans ce cas précis le programme retournera Comparaison: true car la méthode equals compare les contenus des chaines. Cependant cette méthode qui itére les caractères peut être très lente. Alors comment Java optimise ce pattern en interne ? N’en déplaise à mes amis fan de C/C++ les gens qui codent la virtual machine de Java ne sont pas plus bêtes que d’autres, et bien souvent ils ont aussi de bonnes connaissances en C/C++.

L’opérateur == compare l’identité en mémoire des objets, et donc cet appel sera vraiment plus rapide que l’appel de la méthode equals. Si comme dans Xerces-J la comparaison de String est le coeur de votre moteur, il est indispensable de l’optimiser, les gains en terme de performances seront important.
Pour cela ce qu’il faut c’est une liste de Strings à comparer en mémoire dans laquelle nous viendrons piocher lorsque nous devrons comparer une String à notre liste de référence. D’autre part si la String comparée n’existe pas nous voudrons stocker sa référence en mémoire. Avec ce mécanisme il sera possible d’utiliser l’opérateur == pour comparer des instances. C’est le rôle de la méthode intern() de la class String qui gére cette liste et qui nous retourne la référence de la string en mémoire.


    public static void main(String[] args)
    {
        System.out.println("Test 1 "+(new String("Touilleur")==new String("Touilleur")));

        System.out.println("Test 2 "+( (new String("Touilleur").intern()) == (new String("Touilleur").intern())));
    }

Attention aux parenthèses qui sont importantes ici pour que le test soit valide. L'execution de ce programme affichera:

Test 1 false
Test 2 true

La question qui reste en suspend est pourquoi alors une String qui est static et final est instancié avec un appel à intern() ? Nous sommes habitués à voir ce code là:


 public static final String MY_PARAM="params";

moi ce qui m’a étonnné c’est


 public static final String MY_PARAM="params".intern();

Il se trouve que Java fait en sorte que ce genre de pattern soit déjà optimisé. Toutes les Strings d’une class sont par défaut automatiquement « internés » de sorte que vous pouvez avoir quelques optimisations. Le code ci-dessous montre que les String qui peuvent être résolue à la compilation seront optimisées. Si par contre vous lancez le programme en passant test (java QuickTest test) vous verrez que les paramètres dynamiques ne peuvent pas être optimisé et que l’execution du code retournera false.


public class QuickTest
{
    public static final String MY_PARAM="test";

    public static void main(String[] args)
    {
        // Est-ce que test est identique a MY_PARAM ?
        System.out.println("test" == MY_PARAM); // VA AFFICHER TRUE

        // Et si nous concatenons la string
        String s2="te"+"st";
        System.out.println( s2 == MY_PARAM); // VA AFFICHER TRUE

        // Si nous specifions test en tant que premier argument de ce programme
        // afin de voir a l'execution si nous avons une difference
        String s3=args[0];
        System.out.println(s3 == MY_PARAM);  // VA AFFICHER FALSE

        // Maintenant si nous passons par l'appel a intern()
        System.out.println(s3.intern() == MY_PARAM);  // VA AFFICHER TRUE
    }
}

Le 4eme appel dans le code ci-dessus est donc la raison pour laquelle nous pouvons tout à fait ajouter un call intern() sur une constante en Java. Il faut donc simplement que notre code force un appel à intern() pour pouvoir utiliser l’opérateur ==. D’autre part pour revenir au début de ce post, forcer un appel à intern() sur une constante permet de transformer cette constante résolue à la compilation en constante résolue à l’execution. (Voir ) bien que finalement ceci est un intérêt assez limité.

La méthode intern() de la class String est une méthode native. L’implémentation est donc déléguée à la JVM, ce qui fait qu’il y a aussi une difference en terme de performance entre BEA JRockIt et SUN JVM

0 no like

Articles similaires:

Default ThumbnailExemple d'utilisation de java.util.BitSet Default ThumbnailAlert Securité Java AusCert: je vous explique tout Default ThumbnailQuelle est la différence entre un Iterator et une Enumeration ? Default ThumbnailDévelopper en Java avec un Mac et Leopard: il y a tout

Derniers articles

  • L’instant T où tu poses ta dém…

    Retour d’expérience sur la démission et le moment où vous devez quitter une entreprise.

    6 likes

    24 octobre, 2024
  • The « Robinson » projection – comprendre son système d’information

    Nous sommes en juillet 2022 chez Doctolib. Je travaille sur un projet

    5 likes

    22 octobre, 2024
  • Réussir son démarrage comme Staff/Principal Engineer dans une nouvelle entreprise

    Je prépare une présentation avec mon collègue Théotime pour la conférence Cloud

    3 likes

    6 octobre, 2024

Mots clés

Apple (32) Architecture (14) Big Data (5) Conference (8) Devoxx (55) Dev Web (37) Doctolib (2) geekevent (1) groovy (2) Innoteria (11) Java (517) Linux (10) Non classé (15) Perso (266) Recrutement (2) Scala (30) scrum (43) Société (3) Staff Engineer (5) Startup (21) Web 2.0 (67)

Le Touilleur Express

Blog par Nicolas Martignole

Contactez-moi : nicolas@touilleur-express.fr

Suivez-moi sur X (Twitter) : @nmartignole

Copyright© 2008 - 2024 Nicolas Martignole | Tous droits réservés
  • A propos de l’auteur
  • A propos du Touilleur Express
  • Reset Password

Le Touilleur Express