web-dev-qa-db-fra.com

Les primitives Java sont-elles immuables?

Si une méthode a une variable locale i:

int i = 10;

et puis j'attribue une nouvelle valeur:

i = 11;

Cela va-t-il allouer un nouvel emplacement mémoire? Ou simplement remplacer la valeur d'origine?

Cela signifie-t-il que les primitives sont immuables?

35
fYre

Cela va-t-il allouer un nouvel emplacement mémoire? Ou simplement remplacer la valeur d'origine?

Java ne garantit pas vraiment que les variables correspondent aux emplacements de mémoire. Par exemple, votre méthode peut être optimisée de telle sorte que i soit stockée dans un registre - ou même ne pas être stockée du tout, si le compilateur peut voir que vous n'utilisez jamais réellement sa valeur, ou s'il peut suivre le code et utilisez directement les valeurs appropriées.

Mais mettant cela de côté. . . si nous prenons ici comme abstraction le fait qu'une variable locale indique un emplacement de mémoire sur la pile d'appels, alors i = 11 modifiera simplement la valeur de cet emplacement de mémoire. Il n'aura pas besoin d'utiliser un nouvel emplacement de mémoire, car la variable i était la seule chose faisant référence à l'ancien emplacement.

Cela signifie-t-il que les primitives sont immuables?

Oui et non: oui, les primitifs sont immuables, mais non, ce n'est pas à cause de ce qui précède.

Lorsque nous disons que quelque chose est mutable, nous voulons dire qu'il peut être muté: changer tout en conservant la même identité. Par exemple, lorsque vous faites pousser vos cheveux, vous êtes en train de vous muter: vous êtes toujours vous, mais l’un de vos attributs est différent.

Dans le cas des primitives, tous leurs attributs sont entièrement déterminés par leur identité; 1 signifie toujours 1, quoi qu'il en soit, et 1 + 1 est toujours 2. Tu ne peux pas changer ça.

Si une variable int donnée a la valeur 1, vous pouvez la remplacer par la valeur 2, mais il s'agit d'un changement d'identité total: elle n'a plus la même valeur qu'elle avait auparavant. C'est comme changer me pour désigner quelqu'un d'autre au lieu de moi: cela ne change pas réellement moi, cela change simplement me.

Avec les objets, bien sûr, vous pouvez souvent faire les deux:

StringBuilder sb = new StringBuilder("foo");
sb.append("bar"); // mutate the object identified by sb
sb = new StringBuilder(); // change sb to identify a different object
sb = null; // change sb not to identify any object at all

Dans le langage courant, les deux seront décrits comme "changeant sb", car les gens utiliseront "sb" à la fois pour désigner la variable (qui contient une référence) et pour le objet auquel elle fait référence. (quand il se réfère à un). Ce genre de jeu est bon, tant que vous vous souvenez de la distinction quand elle compte.

57
ruakh

Immutable signifie que chaque fois que la valeur de et de l'objet ont changé, une nouvelle référence est créée sur la pile . Vous ne pouvez pas parler d'immutabilité dans le cas de types primitifs, seules les classes d'emballage sont immuables. copy_by_value pas par référence.

Cela ne fait aucune différence si vous transmettez des variables primitives ou des variables de référence, vous transmettez toujours une copie des bits de la variable. Ainsi, pour une variable primitive, vous transmettez une copie des bits représentant la valeur et si vous transmettez une variable de référence d'objet, vous transmettez une copie des bits représentant la référence à un objet.

Par exemple, si vous transmettez une variable int avec la valeur 3, vous transmettez une copie des bits représentant 3.

Une fois qu'une primitive a été déclarée, its primitive type can never change, bien que sa valeur puisse changer.

6
Java Panter

Ce n'est pas une réponse complète, mais c'est un moyen de prouver l'immuabilité des valeurs de type primitif.

Si les valeurs primitives (littéraux) sont mutables, le code suivant fonctionnerait correctement:

int i = 10; // assigned i the literal value of 10
5 = i; // reassign the value of 5 to equal 10
System.out.println(5); // prints 10

Bien sûr, ce n'est pas vrai.

Les valeurs entières, telles que 5, 10 et 11, sont déjà stockées dans la mémoire. Lorsque vous définissez une variable égale à l'une d'entre elles: cela modifie la valeur dans l'emplacement de mémoire où i est.

Vous pouvez le voir ici à travers le bytecode du code suivant:

public void test(){
    int i = 10;
    i = 11;
    i = 10;
}

Bytecode:

// access flags 0x1
public test()V
 L0
  LINENUMBER 26 L0
  BIPUSH 10 // retrieve literal value 10
  ISTORE 1  // store it in value at stack 1: i
 L1
  LINENUMBER 27 L1
  BIPUSH 11 // same, but for literal value 11
  ISTORE 1
 L2
  LINENUMBER 28 L2
  BIPUSH 10 // repeat of first set. Still references the same literal 10. 
  ISTORE 1 
 L3
  LINENUMBER 29 L3
  RETURN
 L4
  LOCALVARIABLE this LTest; L0 L4 0
  LOCALVARIABLE i I L1 L4 1
  MAXSTACK = 1
  MAXLOCALS = 2

Comme vous pouvez le voir dans le bytecode (espérons-le), il fait référence à la valeur littérale (exemple: 10), puis le stocke dans l'emplacement pour la variable i. Lorsque vous modifiez la valeur de i, vous modifiez simplement la valeur stockée dans cet emplacement. Les valeurs elles-mêmes ne changent pas, leur emplacement est.

1
user1181445

Les littéraux primitifs et les variables primitives final sont immuables. Les variables primitives non final sont mutables.

L'identité d'une variable primitive est le nom de cette variable et il est évident qu'une telle identité est immuable.

0
Rostislav Krasny

Oui, ils sont immuables. Ils sont totalement immuables.

Il y a une bonne explication enfouie dans ici . C'est pour Go, mais c'est la même chose en Java. Ou toute autre langue de la famille C.

0
nes1983