Les dessous des Strings.

Les dessous des Strings. - Java - Programmation

Marsh Posté le 28-03-2004 à 05:51:54    

Les String en java ont une implémentation assez particulière, dont voici le détail.
 
Partageons mes frères
 
Les chaînes sont immuables, une fois la chaîne construite il n'est plus possible de la modifier, il n'existe d'ailleur pas de méthodes dans la classe String pour ça. On ne peut donc que créer une nouvelle chaine à partir de l'ancienne (par exemple avec substring()). Ceci est fait ainsi pour des raisons de performances, en particulier dans un contexte multithread.
 
La structure en mémoire des chaînes est la suivante :
on a un tout petit objet (4 mots mémoire) de la classe String qui pointe vers un tableau de char. Dans le petit objet de la classe String on a les champs suivants :

Code :
  1. private char value[];
  2.     private int offset;
  3.     private int count;
  4.     private int hash = 0;


On passe rapidement sur le hash : comme il est très fréquement accédé sur les chaînes, ça vaut le coup de faire un cache (on parcourt ainsi qu'une seule fois le tableau de chars pour le calculer).
Le champ value est le tableau des caratères de la chaîne.
Le champ offset est l'index du premier caractère de la chaîne dans le tableau value.
Le champ count est le nombre de caractères dans la chaîne (on a toujours value.length >= count + offset).
Ne me demandez pas pourquoi les 3 premiers champs ne sont pas "final", je m'en étonne moi-même.
La classe String est aussi munie d'un constructeur très utile, visible uniquement dans son package :  

Code :
  1. String(int offset, int count, char value[]) {
  2. this.value = value;
  3. this.offset = offset;
  4. this.count = count;
  5.     }


 
Toute la feinte consiste à partager au maximum les tableaux de char entre plusieurs chaînes, ainsi faire un substring c'est allouer un objet de 4 mots mémoire, et rien de plus, surtout pas faire une recopie de chaîne :

Code :
  1. return ((beginIndex == 0) && (endIndex == count)) ? this :
  2.     new String(offset + beginIndex, endIndex - beginIndex, value);


On alloue un nouveau petit objet et on partage le tableau avec l'ancienne chaîne.
 
JLS
 
 
Le lendemain du grand soir
 
Les StringBuffer partagent eux-aussi leur tableau de char avec les strings qu'ils génèrent par toString() !
Comment font-ils puisque les StringBuffer sont modifiables, eux ?
Ils possèdent une variable booleenne nommée shared qui dit si leur buffer est partagé avec des sous-chaînes ou non. Lorsqu'on extrait pour la première fois une chaîne du buffer, on met shared à true. Si une modification des caractères existants intervient quand shared est à true (par setChar() ou insert(), par exemple), on copie le buffer, on remet shared à false et on modifie la nouvelle copie (lassant du même coup l'ancien buffer aux chaînes qui se le partagent). On notera que l'opération la plus courante sur un StringBuffer, append() ne nécessite jamais de recopie.
 
 
La chute du communisme
 
Bon, partager c'est bien tout ça, mais si j'ai une chaîne de 10 caratères dont le value fait 35000 chars (venant par exemple d'un StringBuffer) et que toutes les autres chaînes partageant le value sont morte, ça bouffe pas loin de 35ko de trop. C'est pour ça qu'il existe le constructeur String(String), qui crée une nouvelle chaîne en copiant la partie utile du value et c'est son seul rôle bah oui, les chaîne sont immuables, pas de risque de bousiller une instance, donc pas besoin de les copier. Autant vous dire que ce constructeur est très rarement utilisé, et dans des cas bien spécifiques.
 
 
Internalisation
 
Il existe une fonctionalité assez particulière des chaînes qui est l'internalisation. La spec de java précise que toutes les chaînes littérales représentant la même séquence de caratères sont identiques (l'opérateur == renvoie true). Comme la JVM ne peut pas savoir à l'avance si 2 classes ne contiennent pas la même chaine littérale dans leur code source (les classes sont chargées au fil  des besoins), le système maintient un pool de chaînes uniques qu'il utilise pour ce besoin. Ce pool est accessible dans votre programme, par la méthode intern() de la classe String, qui vous renvoie la chaîne du système représentant la même séquence de caractère que votre chaîne, les opérations de comparaison s'en trouveront fortement accélérées.
 
JLS
 
Afficher ses convictions
 
Une des rares méthodes de la classe Object est toString() sensée convertir l'objet en String, selon une méthode par défaut choisie par l'utilisateur. Elle est utilisée en débuggage et par les afficheurs par défaut des interfaces homme-machine. Il est donc important que chaque classe la re-définisse suivant ses besoins.  
 
JLS
 
 
Petite leçon d'universalisme
 
En java, si l'un des arguments de + est une String, l'opérateur devient un opérateur universel de concaténations de chaînes. Son autre argument est d'abord converti en chaîne selon la méthode suivante :
 - null est converti en "null"
 - sur les objets on appelle toString(), si ça renvoit null, on utilise "null".
 - les types primitif sont boxés (int val -> Integer(val)) et on appelle toString() dessus.
 
Ensuite, les 2 arguments sont concaténés dans une nouvelle chaîne (ce n'est donc pas un opérateur commutatif).
 
Une utilisation non-judicieuse de + entraîne une pénalité sur l'allocateur de mémoire qui peut être importante. C'est pourquoi il vaut mieux utiliser un StringBuffer quand on commence à concaténer dans plusieurs instructions.
 
Il est à noter que les + d'une expression sont tous poussés dans un grand StringBuffer, sans surcoût pour l'allocateur (mais pas entre les instructions) :

Code :
  1. String v1 = v2 + v3 + v4 + v5;
  2. String v6 = v1 + v7;


est équivalent à :

Code :
  1. StringBuffer sb = new StringBuffer(v2);
  2. sb.append(v3);
  3. sb.append(v4);
  4. sb.append(v5);
  5. String v1 = sb.toString();
  6. StringBuffer sb2 = new StringBuffer(v1);
  7. sb2.append(v7);
  8. String v6 = sb2.toString();


 
Notons que v1+= v2 est équivalent à v1 = v1 + v2. Mais que c'est mal (because création de chaînes intermédiares). On remplaçera donc systématiquement (je n'ai encore jamais vu de cas où ça ne valait pas le coup) les += par un StringBuffer explicite.
 
Il peut être rentable dans certains cas de recréer la fonction printOn(Writer w) de smalltalk pour certaines hiérarchies d'objets qui devronts s'écrire sur un Writer (la classe StringWriter fait le lien entre StringBuffer et le système des Writers utilisé en entrée-sorties). Attention cependant à ne pas marcher sur les pieds de l'infrastructure de sérialisation mise en place avec l'interface Serializable.
 
JLS
 
 
Tips'n tricks
 
 - utilisez String.valueOf(obj) au lieu de obj.toString() si obj peut être null
 - var1 + var2 + var3 +var4 + " prout" est optimisé en StringBuffer par le compilateur (c'est même conseillé dans la norme), si tout est écrit dans la même expression.
 - utilisez un StringBuffer pour le toString() de vos tableaux et collections (le concat() d'une String provoque obligatoirement une allocation suivie d'une recopie des tableaux de char).
 - si vous allez faire beaucoup de equals() sur la même variable String, faites-le sur sa version internalisée (bon, en réalité, il doit y avoir un problème de conception si vous faites tout le temps le même code).
 - Si vous avez une idée de se que vous allez mettre dans un StringBuffer, donnez-lui la taille estimée dès le début par StringBuffer(int length) (par défaut c'est 16, doublement à chaque fois que c'est trop petit) ; au lieu de, par exemple utiliser l'opérateur +.
 - pensez au partage d'instances, n'aillez pas peur de découper vos chaînes, ça coûte pas grand'chose.
 - n'utilisez pas += pour rallonger une chaîne.
 
 
Voiloù, j'espère que ces petits trucs vous seront utiles.
 
PS : comme la question est récurrente sur le forum, je reprécise :  transformer une chaîne représentant une date en objet de type Date se fait avec un SimpleDateFormat.


Message édité par nraynaud le 28-03-2005 à 17:04:41

---------------
trainoo.com, c'est fini
Reply

Marsh Posté le 28-03-2004 à 05:51:54   

Reply

Marsh Posté le 28-03-2004 à 14:05:14    

nraynaud a écrit :


La classe String est aussi munie d'un constructeur très utile, visible uniquement dans son package :  

Code :
  1. String(int offset, int count, char value[]) {
  2. this.value = value;
  3. this.offset = offset;
  4. this.count = count;
  5.     }



Et il se comporte différemment du

Code :
  1. public String(char[] value, int offset, int count)

?


---------------
Au royaume des sourds, les borgnes sont sourds.
Reply

Marsh Posté le 28-03-2004 à 14:22:28    

c'est vrai que c'est un peu débile cette histoire de final :/
 
sinon, les StringBuffer sont synchronisés, ce qui est bien en soit, mais flingue les performances dès qu'on travaille un peu avec


Message édité par Taz le 28-03-2004 à 14:26:55
Reply

Marsh Posté le 28-03-2004 à 14:27:40    

lirais ca plus tard [:drapo]


---------------
IVG en france
Reply

Marsh Posté le 28-03-2004 à 19:42:46    

Ah je pensais que ct un topic cochon ...   :(  
 
(En fait drapo ...)


Message édité par Mazda3 le 28-03-2004 à 19:43:14
Reply

Marsh Posté le 28-03-2004 à 20:08:03    

:)


---------------
yvele n'est plus.
Reply

Marsh Posté le 28-03-2004 à 20:18:28    

joli titre et joli topic. :jap:
 
 
 

Taz a écrit :

c'est vrai que c'est un peu débile cette histoire de final :/


+1 c'est bizarre ...
 

Taz a écrit :

sinon, les StringBuffer sont synchronisés, ce qui est bien en soit, mais flingue les performances dès qu'on travaille un peu avec


Y a StringBuilder dans le jdk 1.5 qui n'est pas synchronisé ... Et bon, même si c'est un peu plus lourd, on peut pas dire que la synchro des StringBuffer flingue les perfs.

R3g a écrit :


Et il se comporte différemment du

Code :
  1. public String(char[] value, int offset, int count)

?


surement vu que dans ce cas, la classe String n'a aucune garantie que tu ne vas pas modifier le tableau de char ....

Reply

Marsh Posté le 28-03-2004 à 20:43:20    

benou a écrit :


Y a StringBuilder dans le jdk 1.5 qui n'est pas synchronisé ... Et bon, même si c'est un peu plus lourd, on peut pas dire que la synchro des StringBuffer flingue les perfs.

ben si, j'avais fait un programme qui faisait pas mal de traitement de texte (regex; split, join, append, etc) et en utilisant un StringBuffer fais maison, j'ai gagné 20% de vitesse de traitement. l'arrivée d'un StringBuilder est une très bonne chose, j'espère que son usage sera rapidement répandu.
 
edit : il est ou le sujet java1.5 ?


Message édité par Taz le 28-03-2004 à 20:45:32
Reply

Marsh Posté le 28-03-2004 à 21:02:23    

Taz a écrit :

edit : il est ou le sujet java1.5 ?


dans la javafaq ...

Reply

Marsh Posté le 28-03-2004 à 21:05:44    

Taz a écrit :


sinon, les StringBuffer sont synchronisés, ce qui est bien en soit, mais flingue les performances dès qu'on travaille un peu avec

normalement, une synchronisation non utilisé ne coûte rien (mais j'ai la flemme d'aller rechercher le paplard l'expliquant).
Je te soupçonne plutôt d'avoir fait des recopies de buffer implicites (comme j'ai expliqué en heut).
 
 
Sinon, je vous rappelle une certaine tradition hérité de smalltalk : on écrit du code dans le langage cible (java en l'occurence) pour faire plaisir au gugus, et on refait tout en natif par en-dessous, pour des raisons de perfs. Donc il faut se méfier un peu (encore que dans le monde du JIT, cette tradition devrait diminuer).
 
[+1] sur benou pour String(char, int, int), il fait une copie du buffer (de la partie utile du buffer).


---------------
trainoo.com, c'est fini
Reply

Marsh Posté le 28-03-2004 à 21:05:44   

Reply

Marsh Posté le 28-03-2004 à 21:14:51    

nraynaud a écrit :

normalement, une synchronisation non utilisé ne coûte rien (mais j'ai la flemme d'aller rechercher le paplard l'expliquant).
Je te soupçonne plutôt d'avoir fait des recopies de buffer implicites (comme j'ai expliqué en heut).

peut être, le fait est quand faisant mon propre StringBuffer et simplement, j'ai eu de meilleurs performances. maintenant, si tu me dis que c'est pas la synchronisation, ça veut dire que le comportement est un peu chiatique par défaut

Reply

Marsh Posté le 28-03-2004 à 23:17:57    

Bonne initiative  :jap:


Message édité par machinbidule1974 le 28-03-2004 à 23:18:06
Reply

Marsh Posté le 28-03-2004 à 23:37:40    

machinbidule1974 a écrit :

Bonne initiative  :jap:  

j'en ai encore plein des comme ça ...


---------------
trainoo.com, c'est fini
Reply

Marsh Posté le 29-03-2004 à 00:24:40    

mazda3 a écrit :

Ah je pensais que ct un topic cochon ...   :(  
 
(En fait drapo ...)


 
j'aurait proposé: les dessous de palm string
 
 
 
[:dehors]

Reply

Marsh Posté le 29-03-2004 à 00:25:48    

nraynaud a écrit :

j'en ai encore plein des comme ça ...


les dessous des integer ? [:itm]

Reply

Marsh Posté le 29-03-2004 à 00:27:08    

simogeo a écrit :


les dessous des integer ? [:itm]


 
 [:xp1700]  [:snoozy]  [:ddr555]

Reply

Marsh Posté le 29-03-2004 à 18:15:16    

nikel ce topic ;) ca merite un beau drapo

Reply

Marsh Posté le 18-04-2004 à 13:59:41    

ajout de "La chûte du communisme"


Message édité par nraynaud le 18-04-2004 à 14:57:25

---------------
trainoo.com, c'est fini
Reply

Marsh Posté le 18-04-2004 à 14:52:31    

'La chute du communisme' plutôt ?
mais :jap: pour le topic.


Message édité par TBone le 18-04-2004 à 14:52:59

---------------
As the plane took off, the pilot turned to the co-pilot and said, “Have you ever flown solo?” Co-pilot: No. Typically I fly much higher than this.
Reply

Marsh Posté le 18-04-2004 à 14:56:50    

TBone a écrit :

'La chute du communisme' plutôt ?
mais :jap: pour le topic.

ah ? tu crois ? bon, j'édite alors !


---------------
trainoo.com, c'est fini
Reply

Marsh Posté le 29-04-2004 à 23:08:46    

rajouture de "Afficher ses convictions" (toString()) et "Petite leçon d'universalisme" (+)
 
comme d'hab, j'attends les critiques et je corrige les fautes.


---------------
trainoo.com, c'est fini
Reply

Marsh Posté le 30-04-2004 à 08:27:52    

nraynaud a écrit :

ah ? tu crois ? bon, j'édite alors !


bah fais-le alors :D


---------------
As the plane took off, the pilot turned to the co-pilot and said, “Have you ever flown solo?” Co-pilot: No. Typically I fly much higher than this.
Reply

Marsh Posté le 30-04-2004 à 08:49:40    

j'ai pas bien compris le dernier paragraphe :(

Citation :

Il peut être rentable dans certains cas de recréer la fonction printOn(Writer w) de smalltalk pour certaines hiérarchies d'objets qui devronts s'écrire sur un Writer (la classe StringWriter fait le lien entre StringBuffer et le système des Writers utilisé en entrée-sorties). Attention cependant à ne pas marcher sur les pieds de l'infrastructure de sérialisation mise en place avec l'interface Serializable.

Reply

Marsh Posté le 30-04-2004 à 17:08:48    

benou a écrit :

j'ai pas bien compris le dernier paragraphe :(

Citation :

Il peut être rentable dans certains cas de recréer la fonction printOn(Writer w) de smalltalk pour certaines hiérarchies d'objets qui devronts s'écrire sur un Writer (la classe StringWriter fait le lien entre StringBuffer et le système des Writers utilisé en entrée-sorties). Attention cependant à ne pas marcher sur les pieds de l'infrastructure de sérialisation mise en place avec l'interface Serializable.



si tu dois écrire une aggrégation sur un Writer, c'est un peu nul de prendre le toString() de chaque noeud et de l'écrire dans le writer, ça a toutes les chances de créer des objets inutiles donc on fait s'écrire chaque objet sur le writer passé en paramètre, sans concaténation préalable de petits bouts de chaine. Parce que toString() a toutes les chances de d'impliquer des +.
 
La classique hiérarchie des expressions dans un compilateur est le cas typique : le toString() des opérateurs binaires est :

Code :
  1. public String toString() {
  2.   return '(' + leftMember.toString() + ' ' + getOpSymbol() + ' ' + rigthMember.toString() + ')';
  3. }


 
ce qui veut dire pour mettre "(((3+4)*5)/6)" dans un fichier, la création de 3 StringBuffers.
 
avec writeOn() :

Code :
  1. public void writeOn(Writer writer) {
  2.   writer.write('(');
  3.   leftMember.writeOn(writer);
  4.   writer.write(' ');
  5.   writer.write(getOpSymbol());
  6.   writer.write(' ');
  7.   rigthMember.writeOn(writer);
  8.   writer.write(')');
  9. }

plouf, ça va direct au bon endroit.
 
Pour retrouver la facilité de debuggage d'une contaténation de Strings, voici la recette que j'ai appliquée récement :

Code :
  1. // log minimal
  2.             if (Options.DEBUG) {
  3.                 StringWriter out = new StringWriter();
  4.                 writeHTTPRequest(out, myOptions, coinMsg, iWantToBeAnonymous);
  5.                 System.out.println(out.toString());
  6.                 // send data
  7.                 socketOut.write(out.toString());
  8.             } else
  9.                 writeHTTPRequest(socketOut, myOptions, coinMsg,
  10.                         iWantToBeAnonymous);


---------------
trainoo.com, c'est fini
Reply

Marsh Posté le 30-04-2004 à 18:58:23    

pour ca, plutot que d'utiliser un StringWritter, tu as aussi le CharArrayWriter avec sa méthode writeTo(Writer out) qui permet de deverser son contenu dans au autre Writer.
 
Perso, j'ai aussi développé une classe super pratique (je ne comprend pas que je l'ai jamais vu ailleur) : C'est un "buffer" qui fait à la fois OutputStream et InputStream  tu peux écrire dedans (il hérite de OutputStream) et au moment où tu veux lire ce qui est dedans, tu peux en tirer un Inputstream qui se sert du même buffer que le outputstream => pas de recopie inutiles. Tu peux continuer à écrire dedans et récupérer d'autres inputstream plus tard ...
 
Il y aurait moyen de faire la même chose avec des writer/reader avec un tableau de char en interne pour optimiser lputot que de passer par les convertisseur flux binaire <--> flux de char


---------------
ma vie, mon oeuvre - HomePlayer
Reply

Marsh Posté le 19-07-2004 à 17:22:42    

petit problème :  
 
je récupère dans une variable un truc comme ca :  
 
c:\toto\prout\bidule\monjeu.jad  (tel quel)
 
hors c la merde, le \t me fout des tabs...
je voudrais donc faire un replaceAll("\\\\","\\\\" ) pour remplacer les \ en \\, mais ca marche pas...
 
que faire ?
 
sic :  
 
String tata = titi.getAbsolutePath().replaceAll("\\\\","\\\\\\\\" ); marche....


Message édité par Jubijub le 19-07-2004 à 17:46:05

---------------
Jubi Photos : Flickr - 500px
Reply

Marsh Posté le 19-07-2004 à 18:36:47    

Jubijub > utiliser la classe File qui est faite pour manipuler des noms de fichier justement ?

Reply

Marsh Posté le 19-07-2004 à 20:49:26    

oula...
 
je dois construire une ligne de commande qui donne un truc genre (ca donne l'idée) (c laid, c pas cross platform, chef de projet insisde):  
 
cd d:\java\j2me\motorola\wtk1\bin && emulator.exe -xprefs:T720 -xdescriptor:c:\projet\test\jeudebile.jad...
 
sachant que je choppe ces paramètres de partout dans mon appli...et que je parse le rep de l'ému pour sortir le chemin de l'exe...
 
m'enfin ca ca marche...c le passage laid de mon stage : je modifie du code jbuilder laid fait par un gars qui pane rien à l'objet (mon prédecesseur), et moi, humble débutant stagiaire, je dois tout modifier...
 
l'ancien sys d'exécution crée un batch en remplissant les lignes...le truc laid à en mourrir...mon chef de projet a voulu qu'on passe par des processus....
 
voilà [:spamafote]


---------------
Jubi Photos : Flickr - 500px
Reply

Marsh Posté le 19-07-2004 à 21:57:25    

euh, non c'est dans ta variable tu recuperes un tab et pas un '\\' suivi d'un 't'.


---------------
Hey toi, tu veux acheter des minifigurines Lego, non ?
Reply

Marsh Posté le 19-07-2004 à 22:00:24    

? mon pb est résolu maos je comprends pas ta remarque....


---------------
Jubi Photos : Flickr - 500px
Reply

Marsh Posté le 19-07-2004 à 22:08:20    

ben tu dis que tu recuperes une chaine qui contient "blabla\tblabla" , si c'est le cas, y'a pas de tab là dedans; je veux dire que je vois pas bien ou est le probleme [:joce]


---------------
Hey toi, tu veux acheter des minifigurines Lego, non ?
Reply

Marsh Posté le 19-07-2004 à 23:15:37    

ben si la chaine est :  
 
c:\toto
 
elle contient \t, qui est le caractère d'échapement du tab...
 
donc si tu la manipule directement sans la retoucher, Java échappe le t, et ca donne :  
 
c:    toto
 
alors que si auparavant tu neutralises les \ en les doublant (\\) et ben ca marche...saulement pour les remplacer, faut aussi échaper ceux que tu mets...donc au final pour avoir 2 \\, g du foutre \\\\\\\\


---------------
Jubi Photos : Flickr - 500px
Reply

Marsh Posté le 19-07-2004 à 23:31:38    

Jubijub a écrit :

ben si la chaine est :  
 
c:\toto
 
elle contient \t, qui est le caractère d'échapement du tab...
 
donc si tu la manipule directement sans la retoucher, Java échappe le t, et ca donne :  
 
c:    toto

le COMPILO remplace les \t par des tabs dans les chaînes constantes littérales. A l'exécution, si tu récupères un \t au cours d'un parsing de XML par exemple, rien ne sera remplacé.


Message édité par nraynaud le 19-07-2004 à 23:40:18
Reply

Marsh Posté le 19-07-2004 à 23:36:20    

Jubijub a écrit :

ben si la chaine est :  
 
c:\toto
 
elle contient \t, qui est le caractère d'échapement du tab...
 
donc si tu la manipule directement sans la retoucher, Java échappe le t, et ca donne :  
 
c:    toto

ben non.


---------------
Hey toi, tu veux acheter des minifigurines Lego, non ?
Reply

Marsh Posté le 20-07-2004 à 09:53:05    

alors un chemin est une constante litérale :  
 

Code :
  1. import java.io.File;
  2. public class Test {
  3.     public static void main(String[] args) {
  4.         File fichier = new File("c:\toto.txt" );
  5.         System.out.println(fichier.getAbsolutePath());
  6.        
  7.     }
  8. }


 
Output :  
 
c:\bidouille\Test\    oto.txt
 
bilan, ca revient au même...


Message édité par Jubijub le 20-07-2004 à 09:53:38

---------------
Jubi Photos : Flickr - 500px
Reply

Marsh Posté le 20-07-2004 à 10:14:24    

bon, moi j'abandonne.

Reply

Marsh Posté le 20-07-2004 à 10:20:36    

moi tout ce qui m'intéressait ct d'éviter ce comportement...ct ma question, et g trouvé la réponse...
 
si g compris ta remarque, la String dans le sys.out.println est un littéral, et donc est convertie par le compilo, ce qui occasionne le \t ...
 
le fait est qu'en aggrégeant les chemins pour construire ma ligne de commande, si je remplace pas les \ par des \\, les \ disparaissent....ca me faisait le coup pour le jad, à la fin la ligne faisait :  
 
blablabla -Xdescriptor:c:bidouilletestfichier.jad
 
et ca ct pas en faisait un sys.out.println, mais en le sortant dans un exec()


---------------
Jubi Photos : Flickr - 500px
Reply

Marsh Posté le 20-07-2004 à 10:23:46    

tu es *vraiment* lourd !
 

Citation :

3.10.5 String Literals
A string literal consists of zero or more characters enclosed in double quotes. Each character may be represented by an escape sequence.
 
A string literal is always of type String (§4.3.3. A string literal always refers to the same instance (§4.3.1) of class String.
 
StringLiteral:
 " StringCharactersopt "
 
StringCharacters:
 StringCharacter
 StringCharacters StringCharacter
 
StringCharacter:
 InputCharacter but not " or \
 EscapeSequence
 
The escape sequences are described in §3.10.6.
 
As specified in §3.4, neither of the characters CR and LF is ever considered to be an InputCharacter; each is recognized as constituting a LineTerminator.
 
It is a compile-time error for a line terminator to appear after the opening " and before the closing matching ". A long string literal can always be broken up into shorter pieces and written as a (possibly parenthesized) expression using the string concatenation operator + (§15.18.1).
 
The following are examples of string literals:
 
""    // the empty string
"\""    // a string containing " alone
"This is a string"  // a string containing 16 characters
"This is a " +   // actually a string-valued constant expression,
 "two-line string" //  formed from two string literals
 
 
Because Unicode escapes are processed very early, it is not correct to write "\u000a" for a string literal containing a single linefeed (LF); the Unicode escape \u000a is transformed into an actual linefeed in translation step 1 (§3.3) and the linefeed becomes a LineTerminator in step 2 (§3.4), and so the string literal is not valid in step 3. Instead, one should write "\n" (§3.10.6). Similarly, it is not correct to write "\u000d" for a string literal containing a single carriage return (CR). Instead use "\r". Each string literal is a reference (§4.3) to an instance (§4.3.1, §12.5) of class String (§4.3.3). String objects have a constant value. String literals-or, more generally, strings that are the values of constant expressions (§15.28)-are "interned" so as to share unique instances, using the method>String.intern.
 
Thus, the test program consisting of the compilation unit (§7.3):
 
package testPackage;
class Test {
 public static void main(String[] args) {
  String hello = "Hello", lo = "lo";
  System.out.print((hello == "Hello" ) + " " );
  System.out.print((Other.hello == hello) + " " );
  System.out.print((other.Other.hello == hello) + " " );
  System.out.print((hello == ("Hel"+"lo" )) + " " );
  System.out.print((hello == ("Hel"+lo)) + " " );
  System.out.println(hello == ("Hel"+lo).intern());
 }
}
class Other { static String hello = "Hello"; }
 
and the compilation unit:
 
package other;
public class Other { static String hello = "Hello"; }
 
produces the output:
 
true true true true false true
 
This example illustrates six points:
 
    * Literal strings within the same class (§8) in the same package (§7) represent references to the same String object (§4.3.1).
    * Literal strings within different classes in the same package represent references to the same String object.
    * Literal strings within different classes in different packages likewise represent references to the same String object.
    * Strings computed by constant expressions (§15.28) are computed at compile time and then treated as if they were literals.
    * Strings computed at run time are newly created and therefore distinct.
    * The result of explicitly interning a computed string is the same string as any pre-existing literal string with the same contents.

Reply

Marsh Posté le 20-07-2004 à 10:30:33    

Je dois etre très con mais je vois pas en quoi ca concerne mon pb...
 

Code :
  1. public ProjectLauncher(ExecutionConfiguration config, Project project,
  2.             File jadFile, MainFrame main) {
  3.         runJad = config.isExecutionJad();
  4.         runJar = config.isExecutionJar();
  5.         platformName = config.getMobile().getPlatform().getPlatformName();
  6.         emulatorPath = props.getProperty(platformName);
  7.         emulatorParameters = config.getCommandLineParameters();
  8.         projectPath = main.getPathProject(project);
  9.         jarPath = projectPath.concat(project.getProjectName() + "_v"
  10.                 + project.getProjectVersion());
  11.         jadPath = jadFile.getAbsolutePath();
  12.     }
  13.     public void runProject() {
  14.         String path = emulatorPath.substring(0,emulatorPath.lastIndexOf("\\" ));
  15.         String exe = emulatorPath.substring(emulatorPath.lastIndexOf("\\" )+1);
  16.         String tempPath = "cd " + path +" && " + exe + " " + emulatorParameters;
  17.         jadPath = jadPath.replaceAll("\\\\","\\\\\\\\" );
  18.         jarPath = jarPath.replaceAll("\\\\","\\\\\\\\" );
  19.         tempPath = tempPath.replaceAll("%JAD%",jadPath);
  20.         tempPath = tempPath.replaceAll("%JAR%",jarPath);
  21.         System.out.println("path is " + tempPath);
  22.         cmd(tempPath);
  23.     }


 
Si je remplace pas les \, g des merdes de partout...
 


---------------
Jubi Photos : Flickr - 500px
Reply

Marsh Posté le 20-07-2004 à 11:49:22    

nraynaud a écrit :

bon, moi j'abandonne.

+1 [:mlc]


---------------
Hey toi, tu veux acheter des minifigurines Lego, non ?
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed