Pourquoi String est-il immuable en Java?

177

On m'a demandé dans une interview pourquoi String est immuable

J'ai répondu comme ceci:

Lorsque nous créons une chaîne en java comme String s1="hello";alors un objet sera créé dans la piscine de chaîne (bonjour) et s1 pointera à bonjour .Maintenant si encore une fois nous ne String s2="hello";puis un autre objet ne sera pas créé , mais s2 pointera vers hello parce que JVM va d' abord vérifier si le même objet est présent dans le pool de chaînes ou non. S'il n'est pas présent, seul un nouvel objet est créé sinon pas.

Maintenant , si java permet chaîne mutable suppose alors si nous changeons s1 à hello worldalors s2 valeur sera également hello worldsi java chaîne est immuable.

Quelqu'un peut-il me dire si ma réponse est bonne ou mauvaise ?

balancement
la source
46
Pourquoi est toujours difficile de répondre. La réponse la plus correcte est probablement: parce que les concepteurs de langage ont pensé que c'était une bonne idée.
Keppil
1
voir aussi, cette réponse
3
Votre réponse n'est pas sur le point. C ++ std::stringest modifiable, mais ils ont également un pool de chaînes (enfin, plus correctement, un pool de tableaux de caractères).
Siyuan Ren
1
@rocking Pour être honnête, que ce soit juste ou non dépend de la façon dont ils le lisent. Le fait est que Java peut avoir un pool de chaînes car les chaînes sont immuables. S'ils avaient décidé de rendre les chaînes mutables, ils n'auraient pas utilisé de pool de chaînes; il peut donc ne pas être exact de dire "pool de chaînes, donc chaînes immuables"; c'est plutôt l'inverse. Les raisons de choisir des chaînes immuables sont décrites ci-dessous, et le pool de chaînes est une stratégie de travail pour cette raison . Pourtant, votre réponse n'est pas incorrecte , elle ne semble tout simplement pas complète. Vous devrez juste attendre et voir ce qu'ils disent.
Jason C
34
Je ne peux tout simplement pas comprendre pourquoi cette question a été close. La réponse supposée connexe ne concerne même pas Java et n'aborde pas le sujet principal de cette question, qui est «pourquoi». Pour moi, c'est un de ces cas d'une communauté irresponsable agissant sur des questions dont ils ignorent tout. Je l'ai nominé pour rouvrir.
Edwin Dalorzo

Réponses:

163

String est immuable pour plusieurs raisons, voici un résumé:

  • Sécurité : les paramètres sont généralement représentés comme Stringdans les connexions réseau, les URL de connexion à la base de données, les noms d'utilisateur / mots de passe, etc. S'il était modifiable, ces paramètres pourraient être facilement modifiés.
  • Synchronisation et concurrence: rendre String immuable les rend automatiquement thread-safe, résolvant ainsi les problèmes de synchronisation.
  • Mise en cache : lorsque le compilateur optimise vos objets String, il voit que si deux objets ont la même valeur (a = "test", et b = "test") et donc vous n'avez besoin que d'un seul objet string (pour a et b, ces deux pointez sur le même objet).
  • Chargement de classe : Stringest utilisé comme arguments pour le chargement de classe. Si mutable, cela peut entraîner le chargement d'une classe incorrecte (car les objets mutables changent d'état).

Cela étant dit, l'immuabilité de Stringsignifie uniquement que vous ne pouvez pas la modifier à l'aide de son API publique. Vous pouvez en fait contourner l'API normale en utilisant la réflexion. Voir la réponse ici .

Dans votre exemple, si Stringétait mutable, considérez l'exemple suivant:

  String a="stack";
  System.out.println(a);//prints stack
  a.setValue("overflow");
  System.out.println(a);//if mutable it would print overflow
Communauté
la source
14
Comment cela pourrait-il affecter la sécurité?
Archit Maheshwari
2
Quelqu'un peut-il expliquer le chargement de classe avec un exemple si possible?
Viraj
6
Concernant la sécurité, si je suis intéressé par la modification des paramètres de connexion, c'est simple au moment de l'exécution (avec un débogueur, etc.). Concernant le chargement de classe, si Stringest mutable, alors le chargeur de classe prendrait la chaîne passée, ferait une copie et ne changerait pas sa copie. Lorsque vous pensez à un problème avec les mutables java.lang.String, pensez à la façon dont C ++ résout ce problème (car il a des mutables std::string.
Expiation limitée
En ce qui concerne la sécurité, comment une chaîne mutable peut-elle être modifiée lorsque le programme est en cours d'exécution?
MasterJoe2
Puisque String est immuable, son hashcode est mis en cache au moment de la création et il n'a pas besoin d'être calculé à nouveau.
Abdul Alim Shakir
45

Les développeurs Java décident que les chaînes sont immuables en raison des aspects suivants: conception, efficacité et sécurité .

Les chaînes de conception sont créées dans une zone de mémoire spéciale du tas Java appelée «pool de chaînes internes». Pendant que vous créez un nouveau String (pas dans le cas de l'utilisation du constructeur String () ou de toute autre fonction String qui utilise en interne le constructeur String () pour créer un nouvel objet String; le constructeur String () crée toujours une nouvelle constante de chaîne dans le pool, sauf si nous appelez la variable méthode intern () ), il recherche le pool pour vérifier s'il existe déjà. S'il existe, renvoie la référence de l'objet String existant. Si la chaîne n'est pas immuable, la modification de la chaîne avec une référence entraînera une valeur incorrecte pour les autres références.

Selon cet article sur DZone:

La chaîne de sécurité est largement utilisée comme paramètre pour de nombreuses classes Java, par exemple la connexion réseau, l'ouverture de fichiers, etc. Si la chaîne n'était pas immuable, une connexion ou un fichier serait modifié et entraînerait une menace sérieuse pour la sécurité. Les chaînes mutables peuvent également poser des problèmes de sécurité dans Reflection, car les paramètres sont des chaînes.

Efficacité Le hashcode de la chaîne est fréquemment utilisé en Java. Par exemple, dans un HashMap. Être immuable garantit que le hashcode sera toujours le même, de sorte qu'il puisse être mis en cache sans se soucier des changements, ce qui signifie qu'il n'est pas nécessaire de calculer le hashcode à chaque fois qu'il est utilisé.

Alex Mathew
la source
7
Votre compréhension du pool de chaînes est incorrecte. Les constantes de chaîne sont créées dans le pool interne, mais il est parfaitement possible d'avoir plus d'un objet chaîne avec le même texte. Je conviens que les chaînes immuables permettent le regroupement, mais il n'y a pas autant de regroupement que vous l'avez indiqué.
Jon Skeet
@JonSkeet Vous avez raison. String s1 = nouvelle chaîne ("test"); L'instruction crée une nouvelle constante de chaîne dans le pool interne sauf si nous appelons la méthode intern (). Merci d'approfondir mes connaissances sur le pool de stagiaires string.
Alex Mathew
2
C'est plus que simplement utiliser le constructeur de chaîne - presque tout ce qui crée une nouvelle chaîne, par exemple sous-chaîne, fractionnement, concat, etc. créera de nouvelles chaînes. Les constantes de compilation sont le cas particulier ici, pas la norme ...
Jon Skeet
@JonSkeet substring (), concat (), replace (), etc. utilisent en interne le constructeur String pour créer un nouvel objet string. Merci d'avoir amélioré ma réponse.
Alex Mathew
2
@JonSkeet - Toutes ces réponses disent que l'immutabilité améliore la «sécurité», mais n'explique pas comment. Ils renvoient tous à un vague article dzone qui n'aide pas non plus. Les réponses / lien n'expliquent pas comment une chaîne mutable pourrait être modifiée lorsque le code est en cours d'exécution. Pouvez-vous expliquer?
MasterJoe2
25

Nous ne pouvons pas être sûrs de ce que pensaient réellement les concepteurs Java lors de la conception, Stringmais nous ne pouvons conclure ces raisons que sur la base des avantages que nous retirons de l'immuabilité des chaînes, dont certains sont

1. Existence d'un pool de constantes de chaîne

Comme indiqué dans l'article Pourquoi la chaîne est stockée dans le pool de constantes de chaîne , chaque application crée trop d'objets chaîne et afin d'éviter que la JVM ne crée d'abord beaucoup d'objets chaîne, puis les récupère. La JVM stocke tous les objets chaîne dans une zone de mémoire distincte appelée pool de constantes String et réutilise les objets de ce pool mis en cache.

Chaque fois que nous créons un littéral de chaîne, la JVM voit d'abord si ce littéral est déjà présent dans le pool constant ou non et s'il y est, une nouvelle référence commencera à pointer vers le même objet dans SCP.

String a = "Naresh";
String b = "Naresh";
String c = "Naresh";

Dans exemple ci - dessus objet chaîne avec la valeur Nareshsera créée en se SCP qu'une seule fois et toute référence a, b, cpointera vers le même objet , mais si nous essayons de faire des changements dans apar exemple a.replace("a", "").

Idéalement adevrait avoir une valeur Nreshmais b, cdevrait rester inchangé car en tant qu'utilisateur final , nous faisons le changement aseulement. Et nous savons a, b, ctous pointent le même objet , donc si nous faisons un changement a, d' autres devraient également refléter le changement.

Mais l'immuabilité des chaînes nous sauve de ce scénario et en raison de l'immuabilité de l'objet string, l'objet string Nareshne changera jamais. Ainsi, lorsque nous apportons une modification au alieu d'une modification dans l'objet chaîne, la NareshJVM crée un nouvel objet, assignez-le a, puis modifiez cet objet.

Ainsi, le pool de chaînes n'est possible qu'en raison de l'immuabilité de String et si String n'aurait pas été immuable, la mise en cache des objets de chaîne et leur réutilisation n'aurait aucune possibilité car toute variable aurait changé la valeur et corrompu les autres.

Et c'est pourquoi il est géré par JVM très spécialement et dispose d'une zone mémoire spéciale.

2. Sécurité du fil

Un objet est appelé thread-safe lorsque plusieurs threads y opèrent, mais qu'aucun d'entre eux n'est capable de corrompre son état et que l'objet conserve le même état pour chaque thread à tout moment.

Comme nous, un objet immuable ne peut être modifié par personne après sa création, ce qui rend chaque objet immuable est thread-safe par défaut. Nous n'avons pas besoin de lui appliquer des mesures de sécurité des threads telles que la création de méthodes synchronisées.

Ainsi, en raison de sa nature immuable, l'objet string peut être partagé par plusieurs threads et même s'il est manipulé par de nombreux threads, il ne changera pas sa valeur.

3. Sécurité

Dans chaque application, nous devons transmettre plusieurs secrets, par exemple le nom d'utilisateur \ les mots de passe de l'utilisateur, les URL de connexion et, en général, toutes ces informations sont passées en tant qu'objet de chaîne.

Supposons maintenant que si String n'aurait pas été de nature immuable, cela entraînerait une menace sérieuse pour la sécurité de l'application car ces valeurs sont autorisées à être modifiées et si cela est autorisé, elles pourraient être modifiées en raison d'un code mal écrit ou de toute autre personne qui avoir accès à nos références variables.

4. Chargement de classe

Comme indiqué dans Création d'objets via la réflexion en Java avec exemple , nous pouvons utiliser la Class.forName("class_name")méthode pour charger une classe en mémoire qui appelle à nouveau d'autres méthodes pour le faire. Et même JVM utilise ces méthodes pour charger des classes.

Mais si vous voyez clairement, toutes ces méthodes acceptent le nom de la classe en tant qu'objet chaîne, les chaînes sont donc utilisées dans le chargement de la classe java et l'immuabilité fournit la sécurité par laquelle la classe correcte est chargée ClassLoader.

Supposons que String n'aurait pas été immuable et que nous essayions de charger java.lang.Objectce qui est changé org.theft.OurObjectentre et maintenant tous nos objets ont un comportement que quelqu'un peut utiliser pour des choses indésirables.

5. Mise en cache du HashCode

Si nous allons effectuer des opérations liées au hachage sur un objet, nous devons remplacer la hashCode()méthode et essayer de générer un hashcode précis en utilisant l'état de l'objet. Si l'état d'un objet change, cela signifie que son hashcode doit également changer.

Parce que String est immuable, la valeur d'un objet string ne sera jamais modifiée, ce qui signifie que son hashcode ne changera pas non plus, ce qui donne à la classe String l'occasion de mettre en cache son hashcode lors de la création de l'objet.

Oui, l'objet String met en cache son hashcode au moment de la création de l'objet, ce qui en fait le candidat idéal pour les opérations liées au hachage car le hashcode n'a pas besoin d'être calculé à nouveau, ce qui nous fait gagner du temps. C'est pourquoi String est principalement utilisé comme HashMapclé.

En savoir plus sur les raisons pour lesquelles la chaîne est immuable et définitive en Java .

Naresh Joshi
la source
1
Concernant la sécurité - Comment la valeur de la chaîne mutable peut-elle être modifiée en mémoire? Comment une autre personne peut-elle accéder à nos références variables?
MasterJoe2
Il ne s'agit pas de savoir comment accéder aux références, mais que se passe-t-il si quelqu'un y a accès? comme mentionné "si String n'aurait pas été de nature immuable, cela entraînerait une menace sérieuse pour la sécurité de l'application car ces valeurs sont autorisées à être modifiées et si cela est autorisé, elles pourraient être modifiées en raison d'un code mal écrit ou de toute autre personne qui ont accès à nos références variables. "
Naresh Joshi
Le comment compte ici. Il est possible ou non d'accéder aux références. Si possible, pouvez-vous nommer 1 à 2 techniques *** (c'est-à-dire le comment) qui peuvent être utilisées pour le faire? Si ce n'est pas possible, alors le point sur la sécurité n'est pas applicable. *** Exemple - Nommez une technique pour attaquer la base de données d'une application Web -> injection SQL. Connaissez-vous des techniques comme celle-ci pour attaquer les références?
MasterJoe2
Comme mentionné, "Cela peut se produire en raison d'un code mal écrit ou de tout changement effectué par une autre personne ayant accès à nos références de variables". Par exemple, supposons que String soit mutable et que vous écrivez une méthode qui utilise une chaîne une chaîne secrète et encore une fois que la chaîne est passée à plusieurs autres méthodes intermédiaires et que l'une de ces méthodes n'est pas écrite par vous et que cette méthode a apporté des modifications à cela string maintenant après avoir appelé toutes ces méthodes, control a renvoyé votre méthode et vous utilisez à nouveau cette chaîne, mais elle a été modifiée.
Naresh Joshi
2
Veuillez divulguer toute affiliation et ne pas utiliser le site comme un moyen de promouvoir votre site par la publication. Voir Comment rédiger une bonne réponse? .
Yvette
21

Raison la plus importante selon cet article sur DZone:

String Constant Pool ... Si la chaîne est modifiable, la modification de la chaîne avec une référence entraînera une valeur incorrecte pour les autres références.

Sécurité

La chaîne est largement utilisée comme paramètre pour de nombreuses classes Java, par exemple la connexion réseau, l'ouverture de fichiers, etc. Si la chaîne n'était pas immuable, une connexion ou un fichier serait modifié et entraînerait une menace sérieuse pour la sécurité. ...

J'espère que cela vous aidera.

JDGuide
la source
@JasonC Je veux juste savoir si ma réponse est fausse ou non, j'avais déjà assisté à l'entrevue et j'attendais le résultat.Si la réponse leur a été juste, je serai sélectionné
bascule
1
Selon ma connaissance, votre réponse est correcte, mais immuable signifie que la référence ne changera jamais l'emplacement de pointage. Tout le meilleur pour votre entretien.
JDGuide
1
Si vous acceptez votre point n ° 1, tous les objets doivent être immuables.
nicomp
Bonjour JDeveloper, j'ai édité votre réponse pour attribuer correctement la source de votre réponse. N'oubliez pas de toujours utiliser des guillemets pour les copies textuelles du contenu. Merci!
NickL
L'article DZone contient des erreurs majeures sur le fonctionnement du pool Strign. Ce n'est que pour les constantes. Ergo, la justification énoncée est invalide.
Marquis of Lorne
4

J'ai lu cet article Pourquoi la chaîne est immuable ou définitive en Java et suppose que ce qui suit peut être la raison la plus importante:

String est immuable en Java car les objets String sont mis en cache dans le pool String . Étant donné que les littéraux String mis en cache sont partagés entre plusieurs clients, il existe toujours un risque, où l'action d'un client affecterait tous les autres clients.

Tho
la source
1

Vous avez raison. Stringen java utilise le concept de String Poollittéral. Lorsqu'une chaîne est créée et si la chaîne existe déjà dans le pool, la référence de la chaîne existante sera retournée, au lieu de créer un nouvel objet et de renvoyer sa référence.Si une chaîne n'est pas immuable, changer la chaîne avec une référence sera conduit à une valeur erronée pour les autres références.

J'ajouterais encore une chose, car il Stringest immuable, il est sans danger pour le multi-threading et une seule instance de String peut être partagée entre différents threads. Cela évite l'utilisation de la synchronisation pour la sécurité des threads, les chaînes sont implicitement thread safe.

Akshay
la source
0

La classe String FINALsignifie que vous ne pouvez pas créer de classe pour en hériter, changer la structure de base et rendre le Sting mutable.

Une autre variable d'instance et des méthodes de la classe String qui sont fournies sont telles que vous ne pouvez pas changer d' Stringobjet une fois créé.

La raison pour laquelle vous avez ajouté ne rend pas du tout la chaîne immuable, tout cela indique comment la chaîne est stockée dans le tas.

Donner un coup
la source
11
Si la classe est déclarée comme finale, cela signifie que la classe ne peut pas être héritée, mais cela ne signifie pas que les champs d'instances de la classe ne peuvent pas être modifiés et que la classe est donc immuable.
Dmitry Bychenko
@Zeeshan: Les exemples de classes que vous donnez sont tous immuables.
Siyuan Ren
0

La chaîne est donnée comme immuable par les micro-systèmes Sun, car la chaîne peut être utilisée comme clé dans la collection de cartes. StringBuffer est mutable. C'est la raison, il ne peut pas être utilisé comme clé dans l'objet de la carte

chaithanya krishna gogineni
la source
0

La raison la plus importante pour laquelle une chaîne devient immuable en Java est la considération de sécurité . Le suivant serait la mise en cache .

Je crois que d'autres raisons données ici, telles que l'efficacité, la concurrence, la conception et le pool de chaînes découlent du fait que String est rendu immuable. Pour par exemple. String Pool a pu être créé car String était immuable et non l'inverse.

Consultez la transcription de l'entretien avec Gosling ici

D'un point de vue stratégique, ils ont tendance à être plus souvent sans problème. Et il y a généralement des choses que vous pouvez faire avec des immuables que vous ne pouvez pas faire avec des choses mutables, comme mettre en cache le résultat. Si vous passez une chaîne à une méthode d'ouverture de fichier, ou si vous passez une chaîne à un constructeur pour une étiquette dans une interface utilisateur, dans certaines API (comme dans de nombreuses API Windows), vous transmettez un tableau de caractères. Le récepteur de cet objet doit vraiment le copier, car il ne sait rien de la durée de vie de celui-ci. Et ils ne savent pas ce qui arrive à l'objet, s'il est changé sous leurs pieds.

Vous finissez par être presque obligé de répliquer l'objet parce que vous ne savez pas si vous en êtes le propriétaire ou non. Et l'une des bonnes choses à propos des objets immuables est que la réponse est: "Ouais, bien sûr que vous faites." Parce que la question de la propriété, qui a le droit de la changer, n'existe pas.

L'une des choses qui a forcé Strings à être immuable était la sécurité. Vous disposez d'une méthode d'ouverture de fichier. Vous lui passez une chaîne. Et puis il effectue toutes sortes de vérifications d'authentification avant de passer à l'appel du système d'exploitation. Si vous parvenez à faire quelque chose qui a muté efficacement la chaîne, après le contrôle de sécurité et avant l'appel du système d'exploitation, alors boum, vous êtes dedans. Mais les chaînes sont immuables, donc ce genre d'attaque ne fonctionne pas. Cet exemple précis est ce qui exigeait vraiment que les chaînes soient immuables

Sameer Sinha
la source
0

En plus des bonnes réponses, je voulais ajouter quelques points. Comme les chaînes, Array contient une référence au début du tableau, donc si vous créez deux tableaux arr1et que vous avez arr2fait quelque chose comme arr2 = arr1ça, la référence sera arr2identique, car la arr1modification de la valeur de l'un d'entre eux entraînera la modification de l'autre par exemple

public class Main {
    public static void main(String[] args) {
        int[] a = {1, 2, 3, 4};
        int[] b = a;
        a[0] = 8;
        b[1] = 7;
        System.out.println("A: " + a[0] + ", B: " + b[0]);
        System.out.println("A: " + a[1] + ", B: " + b[1]);
        //outputs
        //A: 8, B: 8
        //A: 7, B: 7
    }
}

Non seulement cela causerait des bogues dans le code, mais il peut également (et sera) exploité par un utilisateur malveillant. Supposons que vous ayez un système qui modifie le mot de passe administrateur. L'utilisateur doit d'abord entrer le newPassword, puis le oldPasswordsi le programme oldPasswordest identique au adminPasschangement de mot de passe adminPass = newPassword. disons que le nouveau mot de passe a la même référence que le mot de passe administrateur, donc un mauvais programmeur peut créer une tempvariable pour contenir le mot de passe administrateur avant que les utilisateurs n'entrent des données si le oldPasswordest égal à tempcela change le mot de passe sinonadminPass = temp. Quelqu'un sachant que pourrait facilement entrer le nouveau mot de passe et ne jamais entrer l'ancien mot de passe et abracadabra, il a un accès administrateur. Une autre chose que je n'ai pas comprise en apprenant à propos des chaînes, pourquoi la JVM ne crée-t-elle pas une nouvelle chaîne pour chaque objet et n'a-t-elle pas un emplacement unique en mémoire pour cela et vous pouvez simplement le faire en utilisant new String("str");La raison pour laquelle vous ne voudriez pas toujours utiliser newest parce que la mémoire n'est pas efficace et qu'il est plus lent dans la plupart des cas, en savoir plus .

Qeaxe
la source
0

Si HELLOest votre chaîne, vous ne pouvez pas passer HELLOà HILLO. Cette propriété est appelée propriété d'immutabilité.

Vous pouvez avoir plusieurs variables String pointeur pour pointer HELLO String.

Mais si HELLO est char Array, vous pouvez changer HELLO en HILLO. Par exemple,

char[] charArr = 'HELLO';
char[1] = 'I'; //you can do this

Répondre:

Les langages de programmation ont des variables de données immuables qui peuvent être utilisées comme clés dans une paire clé / valeur. Les variables de chaîne sont utilisées comme clés / index, elles sont donc immuables .

Uddhav Gautam
la source
-1

Du Securitypoint de vue, nous pouvons utiliser cet exemple pratique:

DBCursor makeConnection(String IP,String PORT,String USER,String PASS,String TABLE) {

    // if strings were mutable IP,PORT,USER,PASS can be changed by validate function
    Boolean validated = validate(IP,PORT,USER,PASS);

    // here we are not sure if IP, PORT, USER, PASS changed or not ??
    if (validated) {
         DBConnection conn = doConnection(IP,PORT,USER,PASS);
    }

    // rest of the code goes here ....
}
Darxtrix
la source