Pourquoi les chaînes ne peuvent pas être mutables en Java and.NET Je ne sais pas.
18 réponses
selon Effective Java , chapitre 4, page 73, 2e édition:
" il y a plusieurs bonnes raisons à cela: les classes immuables sont plus faciles à concevoir, mettre en œuvre et à utiliser que les mutable classes. Ils sont moins enclins à l'erreur et sont plus sûrs.
[...]
les objets immuables sont simples. un objet immuable peut être 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 c'est garanti que ces invariants resteront vrais pour toujours, avec aucun effort de ta part.
[...]
les objets immuables sont intrinsèquement sans fil; ils ne nécessitent aucune synchronisation. ils ne peuvent pas être corrompus par des fils multiples accéder simultanément. C'est de loin la méthode la plus simple approche pour la réalisation de la sécurité des threads. En fait, aucun fil ne peut jamais observer tout effet d'un autre fil sur un objet immuable. Donc, 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 intérieurs.
[...]
des objets Immuables faire de grands blocs de construction pour les autres objets, si mutable ou immuable.
[...]
le seul inconvénient réel des classes immuables est qu'elles nécessitent un objet distinct pour chaque valeur distincte.
Il y a au moins deux raisons.
Premier - sécurité http://www.javafaq.nu/java-article1060.html
la principale raison pour laquelle la chaîne a fait immuable était la sécurité. Regardez cette exemple: nous avons une méthode d'ouverture de fichier avec vérification de connexion. On passe une corde à cette méthode pour traiter l'authentification ce qui est nécessaire avant l'appel sera transmis à l'OS. Si String était mutable il a été possible de modifier son contenu après l' vérification de l'authentification avant L'arrivée de L'OS demande de programme, alors il est possibilité de demander n'importe quel dossier. Donc, si vous avez le droit d'ouvrir le fichier texte répertoire utilisateur mais ensuite à la volée lorsque vous parvenez à changer nom du fichier que vous pouvez demander d'ouvrir fichier "passwd" ou tout autre fichier. Puis un le fichier peut être modifié, et il sera possible de se connecter directement à l'OS.
Deuxième-efficacité de mémoire http://hikrish.blogspot.com/2006/07/why-string-class-is-immutable.html
JVM gère en interne la "Chaîne de Piscine." Pour accomplir la mémoire efficacité, JVM référera la chaîne objet de la piscine. Il / elle ne créera pas la nouvelle Chaîne objets. Donc, chaque fois que vous créez une nouvelle chaîne littérale, JVM va vérifier dans la piscine s'il il existe déjà ou pas. Si déjà présent dans le piscine, il suffit de donner le référence au même objet ou à créer le nouvel objet dans la piscine. Il y aura être de nombreuses références pointent vers le même Les objets String, si quelqu'un change la valeur, il aura une incidence sur tous les référence. Donc, le soleil a décidé de faire immuable.
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:
Thead Sécurité:
cordes sont extrêmement largement Utilisé type d'objet. Il est donc plus ou moins garanti d'être utilisé dans un environnement multi-filetés. Les chaînes sont immuables pour s'assurer qu'il est sûr de partager des chaînes entre les threads. Avoir une chaîne immuable assure que lors de passer des chaînes de enfiler Une à l'autre le fil B, le fil B ne peut pas modifier de façon inattendue du thread de la chaîne.
non seulement cela aide à simplifier la tâche déjà assez compliquée de la programmation multi-filetée, mais il aide également à la performance des applications multi-filetées. L'accès aux objets mutables doit être synchronisé d'une façon ou d'une autre quand ils peuvent être consultés à partir de plusieurs threads, pour s'assurer qu'un thread ne tente pas de lire la valeur de votre objet pendant qu'il est modifié par un autre thread. Une synchronisation correcte est à la fois difficile à faire correctement pour le programmeur et coûteuse à l'exécution. Des objets immuables ne peuvent pas être modifiés et n'ont donc pas besoin de synchronisation.
Performance:
bien que String interning ait été mentionné, il ne représente qu'un petit gain en efficacité de mémoire pour les programmes Java. Seules les lettres de ficelles sont internées. Cela signifie que seules les chaînes qui sont identiques dans votre code source partagera le même objet String. Si votre programme crée dynamiquement chaîne sont les mêmes, ils seront représentés 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 sous-jacent de caractères n'a pas besoin d'être copié. Par exemple, disons que vous voulez prendre les cinq premiers caractères de la Chaîne. En Java, on appelle ça myString.substring(0,5). Dans ce case, ce que la méthode substring() fait 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 finiriez avec le suivant:
| 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 originale, ni de la longueur du substrat que nous devons extraire. Ce comportement a également quelques avantages de mémoire, puisque de nombreuses chaînes peuvent partager leur char sous-jacent [].
Filet de sécurité et de performance. Si une chaîne ne peut pas être modifiée, il est sûr et rapide de passer une référence parmi plusieurs threads. Si les chaînes étaient mutables, vous auriez toujours à copier tous les octets de la chaîne à une nouvelle instance, ou fournir la synchronisation. Une application typique Lira une chaîne 100 fois pour chaque fois que cette chaîne doit être modifiée. Voir wikipedia sur immutabilité .
il faut vraiment se demander," pourquoi X devrait être mutable?"Il est préférable de faire défaut à l'immutabilité, en raison des avantages déjà mentionnés par Princesse Fluff . Il devrait être une exception que quelque chose est mutable.
malheureusement la plupart des langages de programmation actuels par défaut à la mutabilité, mais avec un peu de chance à l'avenir, le défaut est plus sur l'immutabilité (voir une liste de souhaits pour le prochain langage de programmation grand public ).
un facteur est que, si les chaînes de caractères étaient mutables, les objets qui stockent les chaînes de caractères devraient prendre soin de stocker des copies, de peur que leurs données internes ne changent sans préavis. Étant donné que les chaînes sont un type assez primitif comme les nombres, il est agréable quand on peut les traiter comme si elles étaient passées par valeur, même si elles sont passées par référence (ce qui aide aussi à sauver sur la mémoire).
chaîne de caractères n'est pas un type primitif, mais vous voulez normalement l'utiliser avec la sémantique de valeur, c.-à-d. comme une valeur.
une valeur est quelque chose que vous pouvez faire confiance ne changera pas derrière votre dos.
Si vous écrivez: String str = someExpr();
Tu ne veux pas que ça change à moins de faire quelque chose avec str.
Chaîne de caractères comme un Objet a naturellement pointeur de la sémantique, pour obtenir la valeur sémantique ainsi, il doit être immuable.
Wow! Je ne peux pas croire la désinformation ici. Les chaînes immuable rien avoir 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 'hacking' une chaîne dans votre application), ils seraient certainement une multitude d'autres possibilités disponibles pour le hacking.
c'est une idée tout à fait nouvelle que L'immutabilité de la chaîne est de traiter les questions de filetage. Hmmm ... Je avoir un objet qui est en train d'être changé par deux fils différents. Comment puis-je résoudre ce problème? synchroniser l'accès à l'objet? Naawww ... ne laissons personne changer d'objet , ça réglera tous nos problèmes de concurrence! En fait, rendons tous les objets immuables, et ensuite nous pouvons enlever le contruct synchronisé du langage Java.
La vraie raison (souligné par d'autres ci-dessus) est l'optimisation de la mémoire. Il est assez commun dans toute demande pour la même un littéral de chaîne pour être utilisés à plusieurs reprises. Il est si commun, en fait, qu'il y a des décennies, de nombreux compilateurs fait de l'optimisation du stockage d'une instance unique d'une chaîne littérale. L'inconvénient de cette optimisation est que le code d'exécution qui modifie une chaîne littérale introduit un problème parce qu'il modifie l'instance pour tout autre code qui la partage. Par exemple, il serait pas bon pour une fonction quelque part dans une demande de changement de la chaîne littérale "chien", "chat". Un printf("chien") résultat: "cat" écrit à stdout. Pour cette raison, il devait y avoir un moyen de se prémunir contre le code qui tente de changer les littérales des cordes (I. E., les rendre immuables). Certains compilateurs (avec le soutien de L'OS) pourraient accomplir ceci en plaçant la chaîne littérale dans un segment spécial de mémoire en lecture seule qui causerait un défaut de mémoire si une tentative d'écriture était faite.
En Java ce qui est connu comme un stage. Le compilateur Java ici suit juste une mémoire standard optimisation réalisée par les compilateurs depuis des décennies. Et pour résoudre le même problème de ces littérales de chaînes modifiées à l'exécution, Java rend tout simplement la classe String immuable (I. e, ne vous donne pas de setters qui vous permettraient de changer le contenu de la chaîne). Les cordes n'auraient pas à être immuables si l'internement des cordes littérales ne se produisait pas.
je sais que c'est une bosse, mais... Sont-ils immuables? Considérons l'exemple suivant.
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 pourriez 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;
}
}
}
qui fait le travail suivant
s.MutableReplaceIndex('1', 0);
s.MutableReplaceIndex('2', 1);
s.MutableReplaceIndex('3', 2);
Conclusion: Ils sont dans un état immuable qui est connu par le compilateur. De Corse, 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 mutable en utilisant des pointeurs en C#. Ce n'est pas la façon dont les pointeurs sont destinés à être utilisés, a une utilisation pratique ou est utilisé en toute sécurité; il est cependant possible, ce qui fléchit l'ensemble de la règle "mutable". Vous pouvez normalement pas modifier un index directement d'une chaîne et c'est le seul moyen. Il y a un moyen d'empêcher cela en refusant les instances de pointeur des cordes ou en faisant une copie quand une corde est pointée vers, mais ni l'un ni l'autre n'est fait, ce qui rend les cordes en C # pas entièrement immuable.
dans la plupart des cas, une" chaîne "est (utilisée/traitée comme) une unité atomique , , , tout comme un nombre .
demander pourquoi les caractères individuels d'une chaîne ne sont pas mutables est donc comme demander pourquoi les bits individuels d'un entier ne sont pas mutables.
Vous devez savoir pourquoi. Il suffit de penser cela.
je déteste le dire, mais malheureusement nous débattons de cela parce que notre langue craint, et nous essayons d'utiliser un seul mot, chaîne de caractères , pour décrire un concept ou une classe d'objet complexe, situé dans le contexte.
nous effectuons des calculs et des comparaisons avec des" chaînes " similaires à la façon dont nous faisons avec des nombres. Si les chaînes (ou entiers) étaient mutables, nous aurions à écrire du code spécial pour verrouiller leurs valeurs dans des formes locales immuables afin d'effectuer tout type de calcul de manière fiable. Par conséquent, il est préférable de penser à une chaîne comme un identificateur numérique, mais au lieu d'être 16, 32, ou 64 bits de long, il pourrait être des centaines de bits de long.
quand quelqu'un dit "string", nous pensons tous à des choses différentes. Ceux qui le considèrent simplement comme un ensemble de caractères, sans but particulier à l'esprit, seront bien sûr consternés que quelqu'un vient de décider qu'ils ne devraient pas être en mesure de manipuler ces caractères. Mais la classe" string " n'est pas qu'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 unité atomique significative de données codées comme un nombre. Quand les gens parlent de "manipuler les cordes", peut-être qu'ils parlent vraiment de manipuler les caractères pour construire les cordes , et un constructeur de cordes est grand pour cela. Pensez juste à un un peu sur ce que le mot" chaîne " signifie vraiment.
réfléchissez un instant à ce que ce serait si les cordes étaient mutables. La fonction API suivante pourrait être piégée pour retourner des informations pour un autre utilisateur si la chaîne de nom d'utilisateur mutable est intentionnellement ou involontairement modifiée par un autre thread alors 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 à propos de 'contrôle d'accès', c'est aussi sur la sécurité et "garantir l'exactitude". Si une méthode ne peut pas être facilement écrite et dépend pour effectuer un calcul simple ou une comparaison fiable, alors il n'est pas sûr de l'appeler, mais il serait sûr de remettre en question le langage de programmation lui-même.
c'est un compromis. Les cordes vont dans le pool de cordes et quand vous créez plusieurs cordes identiques, elles partagent la même mémoire. Les concepteurs ont pensé que cette technique de mémorisation fonctionnerait bien pour le cas commun, puisque les programmes ont tendance à broyer sur les mêmes cordes beaucoup.
l'inconvénient est que les concaténations font beaucoup de cordes supplémentaires qui ne sont que transitoires et deviennent des déchets, ce qui nuit en fait à la performance de la mémoire. Vous avez StringBuffer et StringBuilder (en Java, StringBuilder est aussi dans .NET) à utiliser pour préserver la mémoire dans ces cas.
la décision d'avoir une chaîne mutable en C++ cause beaucoup de problèmes, voir cet excellent article de Kelvin Henney sur maladie de la vache folle .
VACHE = Copie Sur Écriture.
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é à titre de garantie. Pour des exemples voir: Tour de magie en Java
L'immuabilité n'est pas si étroitement liée à la sécurité. Pour cela, au moins dans .NET, vous avez la classe SecureString.
L'immuabilité est bonne. Voir Java Efficace. Si vous deviez copier une Chaîne chaque fois que vous avez passé autour, alors que beaucoup d'erreurs de code. Vous avez aussi de la confusion quant aux modifications qui affectent les références. De la même manière que Integer doit être immuable pour se comporter comme int, les chaînes doivent se comporter comme immuable pour agir comme primitives. Dans c++ passer des chaînes de caractères par valeur fait cela sans mention explicite dans le code source.
il y a 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();
}
}
}
}
chaîne est immuable ( une fois créé ne peut pas être changé ) objet. L'objet créé en tant que chaîne est stocké dans le Pool de chaînes constantes. Chaque objet immuable en Java est sécurisé, ce qui implique que String est également sécurisé .String ne peut pas être utilisé par deux threads simultanément. Chaîne une fois attribué ne peut pas être changé.
String demo = " hello " ;
/ / L'objet ci-dessus est stocké dans constant string pool et sa valeur ne peut pas être modifiée.
demo="Bye" ;
/ / nouvelle chaîne "Bye" créée dans constant pool et référencée par la variable Démo
/ / "hello" string existe toujours dans le pool de constante de chaîne et sa valeur n'est pas dépassée mais nous avons perdu la référence à la"hello "string
c'est surtout pour des raisons de sécurité. Il est beaucoup plus difficile de sécuriser un système Si vous ne pouvez pas faire confiance que vos ficelles sont inviolables.