Pourquoi les chaînes ne peuvent-elles pas être mutées en Java et .NET?


191

Pourquoi ont-ils décidé de rendre Stringimmuable en Java et .NET (et dans d'autres langages)? Pourquoi ne l'ont-ils pas rendu mutable?


13
J'ai eu la même pensée, mais j'ai vérifié l'emplacement original des affiches et j'ai constaté qu'elles venaient de Belgique. Étant donné que cela signifie qu'ils ne sont probablement pas anglophones. Couplé au fait que la plupart des autochtones ont une compréhension lâche de la langue, j'ai décidé de lui laisser un peu de mou.
belugabob

8
Merci bélugabob, mais je ne suis pas une elle, je suis un lui. Apparemment, les gens ne tiennent pas compte des différences culturelles.
chrissie1

7
Mes excuses - chrissie est (généralement) le nom d'une fille au Royaume-Uni - faisant de moi une victime d'une autre différence culturelle :-)
belugabob

Juste une note, dans .NET Stringest en fait modifiable en interne. StringBuilderdans .NET 2.0 mute une chaîne . Je vais juste le laisser ici.
Alvin Wong

En fait, les chaînes .NET sont modifiables. Et ce n'est même pas un hack.
Bitterblue

Réponses:


205

Selon Effective Java , chapitre 4, page 73, 2e édition:

«Il existe de nombreuses bonnes raisons à cela: les classes immuables sont plus faciles à concevoir, à implémenter et à utiliser que les classes mutables. Elles sont moins sujettes aux erreurs et sont plus sûres.

[...]

"Les objets immuables sont simples. Un objet immuable peut être dans exactement un état, l'état dans lequel il a été créé. Si vous vous assurez que tous les constructeurs établissent des invariants de classe, alors il est garanti que ces invariants resteront vrais pour toujours, avec aucun effort de votre part.

[...]

Les objets immuables sont intrinsèquement thread-safe; ils ne nécessitent aucune synchronisation. Ils ne peuvent pas être corrompus par plusieurs threads qui y accèdent simultanément. C'est de loin l'approche la plus simple pour assurer la sécurité des fils. En fait, aucun thread ne peut jamais observer l'effet d'un autre thread sur un objet immuable. Par conséquent, les objets immuables peuvent être partagés librement

[...]

Autres petits points du même chapitre:

Non seulement vous pouvez partager des objets immuables, mais vous pouvez partager leurs éléments internes.

[...]

Les objets immuables constituent d'excellents blocs de construction pour d'autres objets, qu'ils soient mutables ou immuables.

[...]

Le seul véritable inconvénient des classes immuables est qu'elles nécessitent un objet séparé pour chaque valeur distincte.


22
Lisez la deuxième phrase de ma réponse: Les classes immuables sont plus faciles à concevoir, à implémenter et à utiliser que les classes mutables. Ils sont moins sujets aux erreurs et sont plus sûrs.
PRINCESS FLUFF

5
@PRINCESSFLUFF J'ajouterais que le partage de chaînes mutables est dangereux même sur un seul thread. Par exemple, la copie d' un rapport: report2.Text = report1.Text;. Ensuite, un autre, modifier le texte: report2.Text.Replace(someWord, someOtherWord);. Cela modifierait le premier rapport ainsi que le second.
phoog

10
@Sam il n'a pas demandé "pourquoi ils ne peuvent pas être mutables", il a demandé "pourquoi ils ont décidé de rendre immuable" ce qui répond parfaitement.
James

1
@PRINCESSFLUFF Cette réponse ne traite pas spécifiquement des chaînes. C'était la question des PO. C'est tellement frustrant - cela arrive tout le temps sur SO et avec les questions d'immuabilité de String également. La réponse ici parle des avantages généraux de l'immuabilité. Alors pourquoi tous les types ne sont-ils pas immuables? Pouvez-vous revenir en arrière et adresser la chaîne?
Howiecamp

@Howiecamp Je pense que c'est implicite par la réponse que les chaînes auraient pu être mutables (rien n'empêche une classe de chaînes mutable hypothétique d'exister). Ils ont simplement décidé de ne pas le faire par souci de simplicité et parce que cela couvrait les 99% des cas d'utilisation. Ils ont toujours fourni StringBuilder pour les autres cas de 1%.
Daniel García Rubio

102

Il y a au moins deux raisons.

Premièrement - sécurité http://www.javafaq.nu/java-article1060.html

La principale raison pour laquelle String est devenu immuable était la sécurité. Regardez cet exemple: Nous avons une méthode d'ouverture de fichier avec vérification de connexion. Nous transmettons une chaîne à cette méthode pour traiter l'authentification qui est nécessaire avant que l'appel ne soit passé au système d'exploitation. Si String était mutable, il était possible de modifier son contenu après la vérification d'authentification avant que le système d'exploitation ne reçoive la demande du programme, il est alors possible de demander n'importe quel fichier. Donc, si vous avez le droit d'ouvrir un fichier texte dans le répertoire utilisateur, mais à la volée lorsque vous parvenez à changer le nom du fichier, vous pouvez demander d'ouvrir le fichier "passwd" ou tout autre. Ensuite, un fichier peut être modifié et il sera possible de se connecter directement à l'OS.

Deuxièmement - Efficacité de la mémoire http://hikrish.blogspot.com/2006/07/why-string-class-is-immutable.html

JVM gère en interne le "String Pool". Pour atteindre l'efficacité de la mémoire, JVM référencera l'objet String du pool. Il ne créera pas les nouveaux objets String. Ainsi, chaque fois que vous créez un nouveau littéral de chaîne, JVM vérifiera dans le pool s'il existe déjà ou non. S'il est déjà présent dans le pool, donnez simplement la référence au même objet ou créez le nouvel objet dans le pool. Il y aura de nombreuses références pointant vers les mêmes objets String, si quelqu'un change la valeur, cela affectera toutes les références. Ainsi, le soleil a décidé de le rendre immuable.


C'est un bon point sur la réutilisation, et particulièrement vrai si vous utilisez String.intern (). Il aurait été possible de réutiliser sans rendre toutes les chaînes immuables, mais la vie a tendance à se compliquer à ce stade.
jsight

3
Aucune de ces raisons ne me paraît être une raison terriblement valable à notre époque.
Brian Knoblauch

1
Je ne suis pas trop convaincu par l'argument de l'efficacité de la mémoire (c'est-à-dire, lorsque deux ou plusieurs objets String partagent les mêmes données et que l'un est modifié, les deux sont modifiés). Les objets CString dans MFC contournent cela en utilisant le comptage de références.
RobH

7
la sécurité ne fait pas vraiment partie de la raison d'être des chaînes immuables - votre système d'exploitation copiera les chaînes dans les tampons en mode noyau et y effectuera une vérification d'accès, pour éviter les attaques de synchronisation. Tout est vraiment une question de sécurité des threads et de performances :)
snemarch

1
L'argument d'efficacité de la mémoire ne fonctionne pas non plus. Dans un langage natif comme C, les constantes de chaîne sont simplement des pointeurs vers des données dans la section de données initialisées - elles sont de toute façon en lecture seule / immuables. "si quelqu'un change la valeur" - encore une fois, les chaînes du pool sont de toute façon en lecture seule.
wj32

57

En fait, les raisons pour lesquelles la chaîne est immuable en java n'ont pas grand-chose à voir avec la sécurité. Les deux principales raisons sont les suivantes:

Sécurité de la tête:

Les chaînes sont un type d'objet extrêmement largement utilisé. Il est donc plus ou moins garanti d'être utilisé dans un environnement multi-thread. Les chaînes sont immuables pour s'assurer qu'il est sûr de partager des chaînes entre les threads. Le fait d'avoir des chaînes immuables garantit que lors du passage de chaînes du thread A à un autre thread B, le thread B ne peut pas modifier de manière inattendue la chaîne du thread A.

Non seulement cela aide à simplifier la tâche déjà assez compliquée de la programmation multi-thread, mais cela aide également à la performance des applications multi-thread. L'accès aux objets mutables doit en quelque sorte être synchronisé lorsqu'ils sont accessibles à partir de plusieurs threads, pour s'assurer qu'un thread ne tente pas de lire la valeur de votre objet pendant qu'il est en cours de modification par un autre thread. Une synchronisation correcte est à la fois difficile à faire correctement pour le programmeur et coûteuse à l'exécution. Les objets immuables ne peuvent pas être modifiés et n'ont donc pas besoin de synchronisation.

Performance:

Bien que l'internement de chaînes ait été mentionné, il ne représente qu'un petit gain d'efficacité de la mémoire pour les programmes Java. Seuls les littéraux de chaîne sont internés. Cela signifie que seules les chaînes identiques dans votre code source partageront le même objet String. Si votre programme crée dynamiquement des chaînes identiques, elles seront représentées dans différents objets.

Plus important encore, les chaînes immuables leur permettent de partager leurs données internes. Pour de nombreuses opérations de chaîne, cela signifie que le tableau de caractères sous-jacent n'a pas besoin d'être copié. Par exemple, supposons que vous souhaitiez utiliser les cinq premiers caractères de String. En Java, vous appelleriez myString.substring (0,5). Dans ce cas, ce que fait la méthode substring () est simplement de créer un nouvel objet String qui partage le char sous-jacent de myString [] mais qui sait qu'il commence à l'index 0 et se termine à l'index 5 de ce char []. Pour mettre cela sous forme graphique, vous vous retrouveriez avec ce qui suit:

 |               myString                  |
 v                                         v
"The quick brown fox jumps over the lazy dog"   <-- shared char[]
 ^   ^
 |   |  myString.substring(0,5)

Cela rend ce genre d'opérations extrêmement bon marché, et O (1) puisque l'opération ne dépend ni de la longueur de la chaîne d'origine, ni de la longueur de la sous-chaîne que nous devons extraire. Ce comportement présente également certains avantages en matière de mémoire, car de nombreuses chaînes peuvent partager leur char [] sous-jacent.


6
L'implémentation de sous-chaînes en tant que références partageant le sous char[]- jacent est une décision de conception plutôt discutable. Si vous lisez un fichier entier en une seule chaîne et que vous conservez une référence à une sous-chaîne à 1 caractère, le fichier entier devra être conservé en mémoire.
Gabe

5
Exactement, j'ai rencontré ce problème particulier lors de la création d'un robot d'exploration de site Web qui n'avait besoin que d'extraire quelques mots de la page entière. Le code HTML de la page entière était en mémoire, et en raison du partage de sous-chaînes du char [], j'ai conservé tout le code HTML même si je n'avais besoin que de quelques octets. Une solution de contournement consiste à utiliser la nouvelle chaîne (original.substring (.., ..)), le constructeur String (String) fait une copie de la plage appropriée du tableau sous-jacent.
LordOfThePigs

1
Un addendum pour couvrir les modifications ultérieures: Depuis Jave 7, String.substring()effectue une copie complète, afin d'éviter les problèmes mentionnés dans les commentaires ci-dessus. Dans Java 8, les deux champs permettant le char[]partage, à savoir countet offset, sont supprimés, réduisant ainsi l'empreinte mémoire des instances String.
Christian Semrau

Je suis d'accord avec la partie Thead Safety, mais je doute du cas de sous-chaîne.
Gqqnbig

@LoveRight: Vérifiez ensuite le code source de java.lang.String ( grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/… ), ça a été comme ça jusqu'à Java 6 (qui était à jour lorsque cette réponse a été rédigée). J'ai apparemment changé dans Java 7.
LordOfThePigs

28

Sécurité et performances du filetage. Si une chaîne ne peut pas être modifiée, il est sûr et rapide de passer une référence entre plusieurs threads. Si les chaînes étaient mutables, vous devrez toujours copier tous les octets de la chaîne dans une nouvelle instance ou assurer la synchronisation. Une application typique lira une chaîne 100 fois à chaque fois que cette chaîne doit être modifiée. Voir wikipedia sur l' immuabilité .


11

On devrait vraiment se demander "pourquoi X devrait-il être mutable?" Il est préférable de choisir par défaut l'immuabilité, en raison des avantages déjà mentionnés par Princess Fluff . Ce devrait être une exception que quelque chose est mutable.

Malheureusement, la plupart des langages de programmation actuels utilisent par défaut la mutabilité, mais j'espère que dans le futur, la valeur par défaut est davantage sur l'immutabilité (voir Une liste de souhaits pour le prochain langage de programmation grand public ).


7

Hou la la! Je ne peux pas croire la désinformation ici. Strings étant immuable n'ont rien avec la sécurité. Si quelqu'un a déjà accès aux objets dans une application en cours d'exécution (ce qui devrait être supposé si vous essayez de vous prémunir contre quelqu'un qui `` pirate '' un Stringdans votre application), il y aura certainement de nombreuses autres possibilités de piratage.

C'est une idée assez nouvelle dont l'immuabilité Stringrésout les problèmes de filetage. Hmmm ... J'ai un objet qui est modifié par deux threads différents. Comment résoudre ça? synchroniser l'accès à l'objet? Naawww ... ne laissons personne du tout changer l'objet - cela résoudra tous nos problèmes de concurrence désordonnés! En fait, rendons tous les objets immuables, puis nous pourrons supprimer la structure synchronisée du langage Java.

La vraie raison (soulignée par d'autres ci-dessus) est l'optimisation de la mémoire. Il est assez courant dans toute application que le même littéral de chaîne soit utilisé à plusieurs reprises. Il est si courant, en fait, qu'il y a des décennies, de nombreux compilateurs ont optimisé le stockage d'une seule instance d'un Stringlittéral. L'inconvénient de cette optimisation est que le code d'exécution qui modifie un Stringlittéral introduit un problème car il modifie l'instance pour tout autre code qui la partage. Par exemple, il ne serait pas bon pour une fonction quelque part dans une application de changer le Stringlittéral "dog"en "cat". A printf("dog")entraînerait l' "cat"écriture sur stdout. Pour cette raison, il devait y avoir un moyen de se prémunir contre le code qui tente de changerStringlittéraux (c'est-à-dire les rendre immuables). Certains compilateurs (avec le support du système d'exploitation) accompliraient cela en plaçant Stringlittéral dans un segment de mémoire spécial en lecture seule qui provoquerait une erreur de mémoire si une tentative d'écriture était faite.

En Java, cela s'appelle le stage. Le compilateur Java ici ne fait que suivre une optimisation de la mémoire standard effectuée par des compilateurs depuis des décennies. Et pour résoudre le même problème de Stringmodification de ces littéraux au moment de l'exécution, Java rend simplement la Stringclasse immuable (c'est-à-dire, ne vous donne aucun paramètre qui vous permettrait de modifier le Stringcontenu). Strings n'aurait pas à être immuable si l'internement de Stringlittéraux ne se produisait pas.


3
Je ne suis pas du tout d'accord sur l'immuabilité et le commentaire du filetage, il me semble que vous ne comprenez pas tout à fait le point. Et si Josh Bloch, l'un des implémenteurs de Java, dit que c'était l'un des problèmes de conception, comment cela peut-il être de la désinformation?
javashlook

1
La synchronisation coûte cher. Les références aux objets mutables doivent être synchronisées, ce n'est pas le cas pour les objets immuables. C'est une raison pour rendre tous les objets immuables à moins qu'ils ne soient mutables. Les chaînes peuvent être immuables, ce qui les rend plus efficaces dans plusieurs threads.
David Thornley

5
@Jim: L'optimisation de la mémoire n'est pas "LA" raison, c'est "A". La sécurité des threads est également une raison «A», car les objets immuables sont intrinsèquement thread-safe et ne nécessitent aucune synchronisation coûteuse, comme David l'a mentionné. La sécurité des threads est en fait un effet secondaire d'un objet immuable. Vous pouvez considérer la synchronisation comme un moyen de rendre l'objet "temporairement" immuable (ReaderWriterLock le rendra en lecture seule, et un verrou régulier le rendra totalement inaccessible, ce qui le rend bien sûr immuable également).
Triynko

1
@DavidThornley: La création de plusieurs chemins de référence indépendants vers un détenteur de valeur mutable le transforme effectivement en une entité et rend beaucoup plus difficile de raisonner, même en dehors des problèmes de threading. En général, les objets mutables sont plus efficaces que les objets immuables dans les cas où exactement un chemin de référence existera pour chacun, mais les objets immuables permettent au contenu des objets d'être partagé efficacement en partageant des références. Le meilleur modèle est illustré par Stringet StringBuffer, mais malheureusement, peu d'autres types suivent ce modèle.
supercat

7

String n'est pas un type primitif, mais vous voulez normalement l'utiliser avec une sémantique de valeur, c'est-à-dire comme une valeur.

Une valeur est quelque chose dont vous pouvez avoir confiance et qui ne changera pas derrière votre dos. Si vous écrivez: String str = someExpr(); Vous ne voulez pas que cela change à moins que VOUS ne fassiez quelque chose avec str.

Stringcomme un Objecta naturellement une sémantique de pointeur, pour obtenir également une sémantique de valeur, il doit être immuable.


7

Un facteur est que, si Strings était mutable, les objets stockant Strings devraient faire attention à stocker des copies, de peur que leurs données internes ne changent sans préavis. Étant donné que les Strings sont un type assez primitif comme les nombres, c'est bien quand on peut les traiter comme s'ils étaient passés par valeur, même s'ils sont passés par référence (ce qui permet également d'économiser de la mémoire).


6

Je sais que c'est une bosse, mais ... Sont-ils vraiment immuables? Considérer ce qui suit.

public static unsafe void MutableReplaceIndex(string s, char c, int i)
{
    fixed (char* ptr = s)
    {
        *((char*)(ptr + i)) = c;
    }
}

...

string s = "abc";
MutableReplaceIndex(s, '1', 0);
MutableReplaceIndex(s, '2', 1);
MutableReplaceIndex(s, '3', 2);
Console.WriteLine(s); // Prints 1 2 3

Vous pouvez même en faire une méthode d'extension.

public static class Extensions
{
    public static unsafe void MutableReplaceIndex(this string s, char c, int i)
    {
        fixed (char* ptr = s)
        {
            *((char*)(ptr + i)) = c;
        }
    }
}

Ce qui fait le travail suivant

s.MutableReplaceIndex('1', 0);
s.MutableReplaceIndex('2', 1);
s.MutableReplaceIndex('3', 2);

Conclusion: Ils sont dans un état immuable connu du compilateur. Bien sûr, ce qui précède ne s'applique qu'aux chaînes .NET car Java n'a pas de pointeurs. Cependant, une chaîne peut être entièrement modifiable en utilisant des pointeurs en C #. Ce n'est pas la façon dont les pointeurs sont destinés à être utilisés, ont une utilisation pratique ou sont utilisés en toute sécurité; c'est cependant possible, contournant ainsi toute la règle "mutable". Vous ne pouvez normalement pas modifier directement un index d'une chaîne et c'est le seul moyen. Il existe un moyen d'empêcher cela en interdisant les instances de pointeur de chaînes ou en effectuant une copie lorsqu'une chaîne est pointée, mais ni l'un ni l'autre n'est fait, ce qui rend les chaînes en C # pas entièrement immuables.


1
+1. Les chaînes .NET ne sont pas vraiment immuables; en fait, cela se fait tout le temps dans les classes String et StringBuilder pour des raisons de performances.
James Ko

3

Dans la plupart des cas, une "chaîne" est (utilisée / traitée comme / pensée / supposée être) une unité atomique significative , tout comme un nombre .

Demander pourquoi les caractères individuels d'une chaîne ne sont pas mutables revient donc à demander pourquoi les bits individuels d'un entier ne sont pas mutables.

Tu devrais savoir pourquoi. Pensez-y.

Je déteste le dire, mais malheureusement, nous en débattons parce que notre langage est nul, et nous essayons d'utiliser un seul mot, une chaîne , pour décrire un concept ou une classe d'objet complexe et contextuellement situé.

Nous effectuons des calculs et des comparaisons avec des «chaînes», comme nous le faisons avec des nombres. Si les chaînes (ou les entiers) étaient mutables, nous aurions à écrire un code spécial pour verrouiller leurs valeurs dans des formes locales immuables afin d'effectuer n'importe quel type de calcul de manière fiable. Par conséquent, il est préférable de penser à une chaîne comme un identifiant numérique, mais au lieu d'avoir une longueur de 16, 32 ou 64 bits, elle pourrait comporter des centaines de bits.

Quand quelqu'un dit "string", nous pensons tous à des choses différentes. Ceux qui le considèrent simplement comme un ensemble de personnages, sans but particulier en tête, seront bien sûr consternés que quelqu'un vient de décider de ne pas pouvoir manipuler ces personnages. Mais la classe "string" n'est pas seulement un tableau de caractères. C'est un STRING, pas un char[]. Il y a quelques hypothèses de base sur le concept que nous appelons une «chaîne», et il peut généralement être décrit comme une unité atomique significative de données codées comme un nombre. Quand les gens parlent de "manipuler des chaînes", ils parlent peut-être vraiment de manipuler des caractères pour créer des chaînes , et un StringBuilder est parfait pour cela.

Considérez un instant ce que ce serait si les chaînes étaient mutables. La fonction API suivante pourrait être amenée à renvoyer des informations pour un utilisateur différent si la chaîne de nom d'utilisateur mutable est intentionnellement ou non modifiée par un autre thread pendant que cette fonction l'utilise:

string GetPersonalInfo( string username, string password )
{
    string stored_password = DBQuery.GetPasswordFor( username );
    if (password == stored_password)
    {
        //another thread modifies the mutable 'username' string
        return DBQuery.GetPersonalInfoFor( username );
    }
}

La sécurité n'est pas seulement une question de «contrôle d'accès», c'est aussi une question de «sécurité» et de «garantie d'exactitude». Si une méthode ne peut pas être facilement écrite et dépendante pour effectuer un simple calcul ou une comparaison de manière fiable, il n'est pas sûr de l'appeler, mais il serait prudent de remettre en question le langage de programmation lui-même.


En C #, une chaîne est modifiable par son pointeur (utilisation unsafe) ou simplement par réflexion (vous pouvez obtenir le champ sous-jacent facilement). Cela rend le point sur la sécurité vide, comme toute personne qui veut intentionnellement changer une chaîne, peut le faire assez facilement. Cependant, cela fournit une sécurité aux programmeurs: à moins que vous ne fassiez quelque chose de spécial, la chaîne est garantie immuable (mais ce n'est pas threadsafe!).
Abel

Oui, vous pouvez modifier les octets de n'importe quel objet de données (string, int, etc.) via des pointeurs. Cependant, nous parlons de la raison pour laquelle la classe string est immuable dans le sens où elle n'a pas de méthode publique intégrée pour modifier ses caractères. Je disais qu'une chaîne ressemble beaucoup à un nombre dans la mesure où la manipulation de caractères individuels n'a pas plus de sens que la manipulation de bits individuels d'un nombre (lorsque vous traitez une chaîne comme un jeton entier (pas comme un tableau d'octets), et un nombre comme une valeur numérique (pas comme un champ de bits). Nous parlons au niveau de l'objet conceptuel, pas au niveau du sous-objet.
Triynko

2
Et juste pour clarifier, les pointeurs dans le code orienté objet sont intrinsèquement dangereux, précisément parce qu'ils contournent les interfaces publiques définies pour une classe. Ce que je disais, c'est qu'une fonction pouvait être facilement trompée si l'interface publique d'une chaîne permettait de la modifier par d'autres threads. Bien sûr, il peut toujours être trompé en accédant aux données directement avec des pointeurs, mais pas aussi facilement ou involontairement.
Triynko

1
«Les pointeurs dans le code orienté objet sont intrinsèquement dangereux» à moins que vous ne les appeliez des références . Les références en Java ne sont pas différentes des pointeurs en C ++ (seule l'arithmétique des pointeurs est désactivée). Un concept différent est la gestion de la mémoire qui peut être gérée ou manuelle, mais c'est une chose différente. Vous pourriez avoir une sémantique de référence (pointeurs sans arithmétique) sans avoir GC (l'inverse serait plus difficile en ce sens que la sémantique de l'accessibilité serait plus difficile à rendre claire, mais pas infaisable)
David Rodríguez - dribeas

L'autre chose est que si les chaînes sont presque immuables, mais pas tout à fait, (je ne connais pas assez la CLI ici), cela peut être vraiment mauvais pour des raisons de sécurité. Dans certaines implémentations Java plus anciennes, vous pouvez le faire, et j'ai trouvé un extrait de code qui l'utilisait pour internaliser les chaînes (essayez de localiser une autre chaîne interne qui a la même valeur, partagez le pointeur, supprimez l'ancien bloc de mémoire) et utilisé la porte dérobée pour réécrire le contenu de la chaîne en forçant un comportement incorrect dans une classe différente. (Pensez à réécrire "SELECT *" en "DELETE")
David Rodríguez - dribeas

3

L'immuabilité n'est pas si étroitement liée à la sécurité. Pour cela, au moins dans .NET, vous obtenez la SecureStringclasse.

Edition ultérieure: En Java, vous trouverez GuardedStringune implémentation similaire.


2

La décision d'avoir une chaîne mutable en C ++ pose beaucoup de problèmes, voir cet excellent article de Kelvin Henney sur Mad COW Disease .

COW = Copie en écriture.


2

C'est un compromis. Strings vont dans le Stringpool et lorsque vous créez plusieurs Strings identiques, ils partagent la même mémoire. Les concepteurs ont pensé que cette technique d'économie de mémoire fonctionnerait bien pour le cas courant, car les programmes ont tendance à broyer beaucoup les mêmes chaînes.

L'inconvénient est que les concaténations font beaucoup de Strings supplémentaires qui ne sont que transitionnels et deviennent simplement des déchets, nuisant en fait aux performances de la mémoire. Vous avez StringBufferet StringBuilder(en Java, StringBuilderest également dans .NET) à utiliser pour préserver la mémoire dans ces cas.


1
Gardez à l'esprit que le "pool de chaînes" n'est pas automatiquement utilisé pour TOUTES les chaînes sauf si vous utilisez explicitement les chaînes ed "inter ()".
jsight

2

StringLes s en Java ne sont pas vraiment immuables, vous pouvez changer leur valeur en utilisant la réflexion et / ou le chargement de classe. Vous ne devriez pas dépendre de cette propriété pour la sécurité. Pour des exemples, voir: Magic Trick en Java


1
Je crois que vous ne pourrez faire de telles astuces que si votre code fonctionne en toute confiance, il n'y a donc aucune perte de sécurité. Vous pouvez également utiliser JNI pour écrire directement sur l'emplacement mémoire où les chaînes sont stockées.
Antoine Aubry

En fait, je crois que vous pouvez changer n'importe quel objet immuable par réflexion.
Gqqnbig

0

L'immuabilité est bonne. Voir Java efficace. Si vous deviez copier une chaîne à chaque fois que vous la passiez, alors ce serait beaucoup de code sujet aux erreurs. Vous ne savez pas non plus quelles modifications affectent quelles références. De la même manière qu'Integer doit être immuable pour se comporter comme int, les chaînes doivent se comporter comme immuables pour agir comme des primitives. En C ++, le passage des chaînes par valeur le fait sans mention explicite dans le code source.


0

Il existe une exception pour presque toutes les règles:

using System;
using System.Runtime.InteropServices;

namespace Guess
{
    class Program
    {
        static void Main(string[] args)
        {
            const string str = "ABC";

            Console.WriteLine(str);
            Console.WriteLine(str.GetHashCode());

            var handle = GCHandle.Alloc(str, GCHandleType.Pinned);

            try
            {
                Marshal.WriteInt16(handle.AddrOfPinnedObject(), 4, 'Z');

                Console.WriteLine(str);
                Console.WriteLine(str.GetHashCode());
            }
            finally
            {
                handle.Free();
            }
        }
    }
}

-1

C'est en grande partie pour des raisons de sécurité. Il est beaucoup plus difficile de sécuriser un système si vous ne pouvez pas croire que vos Strings sont inviolables.


1
Pouvez-vous donner un exemple de ce que vous entendez par «inviolable». Cette réponse semble vraiment hors de son contexte.
Gergely Orosz
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.