web-dev-qa-db-fra.com

String est immuable. Quel est exactement le sens?

J'ai écrit le code suivant sur les chaînes immuables.

public class ImmutableStrings {

    public static void main(String[] args) {
        testmethod();
    }

    private static void testmethod() {
        String a = "a";
        System.out.println("a 1-->" + a);
        a = "ty";
        System.out.println("a 2-->" + a);
    }
}

Sortie:

a 1-->a  
a 2-->ty

Ici, la valeur de la variable a a été modifiée (alors que beaucoup disent que le contenu des objets immuables ne peut pas être modifié). Mais que veut-on dire exactement par String est immuable ? Pourriez-vous s'il vous plaît clarifier ce sujet pour moi?

source: https://docs.Oracle.com/javase/tutorial/Java/nutsandbolts/datatypes.html

189
Anuj Balan

Avant d’aller plus loin dans le tourbillon de immuabilité , jetons un coup d’œil à la classe String et à ses fonctionnalités un peu avant de tirer quelque conclusion que ce soit. .

Voici comment String fonctionne:

String str = "knowledge";

Comme d'habitude, cela crée une chaîne contenant "knowledge" et lui attribue une référence str. Assez simple? Permet d'effectuer d'autres fonctions:

 String s = str;     // assigns a new reference to the same string "knowledge"

Voyons comment fonctionne la déclaration ci-dessous:

  str = str.concat(" base");

Ceci ajoute une chaîne " base" à str. Mais attendez, comment est-ce possible, puisque les objets String sont immuables? Eh bien à votre grande surprise, ça l'est.

Lorsque l'instruction ci-dessus est exécutée, le VM prend la valeur de String str, c'est-à-dire "knowledge" et ajoute " base" en nous donnant la valeur "knowledge base". Maintenant, puisque Strings sont immuables, le VM ne peut pas affecter cette valeur à str, il crée donc un nouvel objet String et lui donne la valeur "knowledge base", et lui donne la référence str.

Un point important à noter ici est que, alors que l'objet String est immuable, sa variable de référence n'est pas. C'est pourquoi, dans l'exemple ci-dessus, il a été fait référence à un nouvellement formé String objet.

À ce stade de l'exemple ci-dessus, nous avons deux objets String: le premier que nous avons créé avec la valeur "knowledge", pointé par s, et le second "knowledge base", pointé par str. Mais, techniquement, nous avons trois objets String, le troisième étant le littéral "base" dans l'instruction concat.

Informations importantes sur l'utilisation de la chaîne et de la mémoire

Et si nous n'avions pas une autre référence s à "knowledge"? Nous aurions perdu cette String. Cependant, il aurait toujours existé, mais serait considéré comme perdu du fait de l'absence de références. Regardez un autre exemple ci-dessous

String s1 = "Java";
s1.concat(" rules");
System.out.println("s1 refers to "+s1);  // Yes, s1 still refers to "Java"

Qu'est-ce qui se passe:

  1. La première ligne est assez simple: créez une nouvelle String"Java" et faites référence à s1.
  2. Ensuite, le VM crée un autre nouveau String"Java rules", mais rien n'y fait référence. Ainsi, la seconde String est instantanément perdue. Nous ne pouvons pas l'atteindre.

La variable de référence s1 fait toujours référence à l'original String"Java".

Presque toutes les méthodes, appliquées à un objet String afin de le modifier, créent un nouvel objet String. Alors, où vont ces objets String? Eh bien, ceux-ci existent en mémoire et l'un des objectifs clés de tout langage de programmation est d'utiliser efficacement la mémoire.

Au fur et à mesure que les applications se développent, il est très courant que les littéraux String occupent une grande surface de mémoire, ce qui peut même entraîner une redondance. rendre Java plus efficace, la machine virtuelle Java met de côté une zone de mémoire spéciale appelée "pool de chaînes constant".

Lorsque le compilateur voit un littéral String, il recherche le String dans le pool. Si une correspondance est trouvée, la référence au nouveau littéral est dirigée vers l'objet String existant et aucun nouvel objet String n'est créé. Le String existant a simplement une autre référence. Voici le but de rendre String objets immuables:

Dans le pool constant String, un objet String est susceptible de comporter une ou plusieurs références. Si plusieurs références pointent sur la même String sans même le savoir, il serait mauvais que l'une des références modifie cette valeur String. C'est pourquoi les objets String sont immuables.

Eh bien, maintenant vous pourriez dire que faire si quelqu'un annule la fonctionnalité de la classe String class C'est la raison pour laquelle le String la classe est marquée final afin que personne ne puisse remplacer le comportement de ses méthodes.

388
roger_that

La chaîne est immuable signifie que vous ne pouvez pas modifier l'objet lui-même, mais vous pouvez modifier la référence à l'objet.

Lorsque vous exécutez a = "ty", vous changez la référence de a en un nouvel objet créé par le littéral chaîne "ty".

Changer un objet signifie utiliser ses méthodes pour changer un de ses champs (ou les champs sont publics et non finaux, afin qu'ils puissent être mis à jour de l'extérieur sans y accéder via des méthodes), par exemple:

Foo x = new Foo("the field");
x.setField("a new field");
System.out.println(x.getField()); // prints "a new field"

Alors que dans une classe immuable (déclarée comme finale, pour empêcher toute modification via l'héritage) (ses méthodes ne peuvent pas modifier ses champs, et les champs sont toujours privés et il est recommandé de les définir comme final), par exemple String, vous ne pouvez pas modifier le String actuel, mais vous peut renvoyer une nouvelle chaîne, c'est-à-dire:

String s = "some text";
s.substring(0,4);
System.out.println(s); // still printing "some text"
String a = s.substring(0,4);
System.out.println(a); // prints "some"
171
Eng.Fouad

Vous changez ce que afait référence à. Essaye ça:

String a="a";
System.out.println("a 1-->"+a);
String b=a;
a="ty";
System.out.println("a 2-->"+a);
System.out.println("b  -->"+b);

Vous verrez que le objet auquel a puis b n'a pas changé.

Si vous souhaitez empêcher votre code de changer à quel objet a se réfère, essayez:

final String a="a";
18
Greg Hewgill

Une chaîne est un char[] contenant une série de nités de code UTF-16 , un décalage int dans ce tableau et une longueur int.

Par exemple.

String s

Il crée un espace pour une référence de chaîne. L'affectation de copies référence autour mais ne modifie pas les objets auxquels ces références font référence.

Vous devez également savoir que

new String(s)

ne fait vraiment rien d'utile. Il crée simplement une autre instance soutenue par le même tableau, le même offset et la même longueur que s. Il y a très rarement une raison de le faire, c'est donc considéré comme une mauvaise pratique par la plupart des Java programmeurs.

Les chaînes entre guillemets Java telles que "my string" sont réellement des références à internedString instances, donc "bar" est une référence à la même instance String, quel que soit le nombre de fois où elle apparaît votre code.


Le "hello" crée une instance mise en pool et la new String(...) crée une instance non mise en pool. Essayez System.out.println(("hello" == "hello") + "," + (new String("hello") == "hello") + "," + (new String("hello") == new String("hello"))); et vous devriez voir true,false,false

5
Lion

immuable signifie que vous ne pouvez pas modifier la valeur de la même référence. Chaque heure nécessaire pour créer une nouvelle référence signifie un nouvel emplacement mémoire. ex:

String str="abc";
str="bcd";

ici, dans le code ci-dessus, il y a 2 blocs dans la mémoire pour stocker la valeur. Le premier pour la valeur "abc" et le second pour "bcd". La deuxième valeur n'est pas remplacée par la première.

c'est ce qu'on appelle l'immuable.

4
Rakesh Patel

vois ici

class ImmutableStrings {

    public static void main(String[] args) {
        testmethod();
    }

    private static void testmethod() {
    String a="a";
    System.out.println("a 1-->"+a);
    System.out.println("a 1 address-->"+a.hashCode());

    a = "ty";
    System.out.println("a 2-->"+a);

       System.out.println("a 2 address-->"+a.hashCode());
    }
}

sortie:

a 1-->a
a 1 address-->97
a 2-->ty
a 2 address-->3717

Cela indique que chaque fois que vous modifiez le contenu d'un objet chaîne immuable a, un nouvel objet est créé. c'est-à-dire que vous n'êtes pas autorisé à modifier le contenu d'un objet immuable. c'est pourquoi les adresses sont différentes pour l'objet.

3
Rustam

Dans votre exemple, la variable a est simplement une référence à une instance d'un objet chaîne. Lorsque vous dites a = "ty", vous ne modifiez pas réellement l'objet chaîne, mais vous pointez plutôt la référence sur une instance totalement différente de la classe string.

3
Jon Newmuis
String S1="abc";
S1.concat("xyz");
System.out.println("S1 is", + S1);
String S2=S1.concat("def");
System.out.println("S2 is", + S2);

Cela montre qu'une fois qu'un objet chaîne est créé, il ne peut plus être modifié. EveryTime vous devez créer nouveau et mettre dans une autre chaîne. S

2
Surya

Un objet immuable est un objet dont l'état ne peut pas être modifié après sa création.

Donc, a = "ABC" <- objet immuable. "a" fait référence à l'objet. Et, a = "DEF" <- un autre objet immuable, "a" en fait référence maintenant.

Une fois que vous avez affecté un objet chaîne, cet objet ne peut plus être modifié en mémoire.

En résumé, vous avez changé la référence à "a" en un nouvel objet chaîne.

2

Java String est immuable, String Stockera la valeur sous la forme d'un objet. Donc, si vous attribuez la valeur String a="a";, il créera un objet et la valeur y sera stockée. Encore une fois, si vous affectez la valeur a="ty" signifie que cela créera un autre objet et enregistrera la valeur, si voulez comprendre clairement, vérifiez le has code pour le String.

2
Selva

Je pense que le code suivant efface la différence:

String A = new String("Venugopal");
String B = A;

A = A +"mitul";

System.out.println("A is " + A);
System.out.println("B is " + B);

StringBuffer SA = new StringBuffer("Venugopal");
StringBuffer SB = SA;

SA = SA.append("mitul");

System.out.println("SA is " + SA);
System.out.println("SB is " + SB);
2
Ankit Sinha

Vous ne modifiez pas l'objet dans l'instruction d'affectation, vous remplacez un objet immuable par un autre. L'objet String("a") ne change pas en String("ty"), il est ignoré et un référence à ty est écrit à la place dans a.

En revanche, StringBuffer représente un objet mutable. Tu peux le faire:

StringBuffer b = new StringBuffer("Hello");
System.out.writeln(b);
b.append(", world!");
System.out.writeln(b);

Ici, vous n'avez pas réaffecté b: il pointe toujours sur le même objet, mais le conten de cet objet a changé.

2
dasblinkenlight

Vous obtenez en fait une référence à une nouvelle chaîne, la chaîne elle-même n'est pas modifiée car elle est immuable. Ceci est pertinent.

Voir

Objets immuables sur Wikipedia

2
Jordan

String est immuable, cela signifie que le contenu de l'objet String ne peut pas être modifié une fois qu'il est créé. Si vous souhaitez modifier le contenu, vous pouvez opter pour StringBuffer/StringBuilder au lieu de String. StringBuffer et StringBuilder sont des classes mutables.

1
user095736

J'espère que le code ci-dessous clarifiera vos doutes:

public static void testString() {
    String str = "Hello";
    System.out.println("Before String Concat: "+str);
    str.concat("World");
    System.out.println("After String Concat: "+str);
    StringBuffer sb = new StringBuffer("Hello");
    System.out.println("Before StringBuffer Append: "+sb);
    sb.append("World");
    System.out.println("After StringBuffer Append: "+sb);
}

Avant String Concat: Bonjour
After String Concat: Bonjour
Avant StringBuffer Ajouter: Bonjour
Après StringBuffer Append: HelloWorld

1
technolisha

Toutes les réponses fournies ci-dessus sont probablement correctes, mais ma réponse est spécifique à l'utilisation de la méthode hashCode(), pour prouver les points tels que String ... une fois créée, elle ne peut pas être modifiée et les modifications entraînent la création d'une nouvelle valeur avec une mémoire différente. emplacement.

public class ImmutabilityTest {

    private String changingRef = "TEST_STRING";

    public static void main(String a[]) {

        ImmutabilityTest dn = new ImmutabilityTest();

        System.out.println("ChangingRef for TEST_STRING OLD : "
                + dn.changingRef.hashCode());

        dn.changingRef = "NEW_TEST_STRING";
        System.out.println("ChangingRef for NEW_TEST_STRING : "
                + dn.changingRef.hashCode());

        dn.changingRef = "TEST_STRING";
        System.out.println("ChangingRef for TEST_STRING BACK : "
                + dn.changingRef.hashCode());

        dn.changingRef = "NEW_TEST_STRING";
        System.out.println("ChangingRef for NEW_TEST_STRING BACK : "
                + dn.changingRef.hashCode());

        String str = new String("STRING1");
        System.out.println("String Class STRING1 : " + str.hashCode());

        str = new String("STRING2");
        System.out.println("String Class STRING2 : " + str.hashCode());

        str = new String("STRING1");
        System.out.println("String Class STRING1 BACK : " + str.hashCode());

        str = new String("STRING2");
        System.out.println("String Class STRING2 BACK : " + str.hashCode());

    }
}

SORTIE

ChangingRef for TEST_STRING OLD : 247540830
ChangingRef for NEW_TEST_STRING : 970356767
ChangingRef for TEST_STRING BACK : 247540830
ChangingRef for NEW_TEST_STRING BACK : 970356767
String Class STRING1 : -1163776448
String Class STRING2 : -1163776447
String Class STRING1 BACK : -1163776448
String Class STRING2 BACK : -1163776447
1

Si un objet bar contient une référence à un objet mutable fooet encapsule une partie de son état dans les aspects modifiables de l'état de foo, cela permettra au code de changez ces aspects de foo pour changer les aspects correspondants de l'état de barsans réellement toucher bar ni même connaître son existence. En règle générale, cela signifie que les objets qui encapsulent leur propre état à l'aide d'objets mutables doivent s'assurer qu'aucune référence à ces objets n'est exposée à un code susceptible de les transformer de manière inattendue. En revanche, si bar contient une référence à un objet moo et n'utilise que des aspects immuables de mooautre que l'identité pour encapsuler son état, alors bar peut librement exposer moo à un code extérieur sans se soucier de ce que le code extérieur pourrait lui faire.

1
supercat

Seule la référence change. D'abord, a faisait référence à la chaîne "a", et plus tard, vous l'avez changée en "ty". La chaîne "a" reste la même.

1
Bhesh Gurung

Dans votre exemple, a fait d'abord référence à "a", puis à "ty". Vous ne modifiez aucune instance String; vous ne faites que changer le nom de String instance a. Par exemple, ceci:

String a = "a";
String b = a; // b refers to the same String as a
a = "b"; // a now refers to a different instance
System.out.println(b);

affiche "a", car nous ne mutons jamais l'instance String à laquelle b pointe.

1
ruakh