web-dev-qa-db-fra.com

Est un entier immuable

Je sais que c'est probablement très stupide, mais beaucoup d'endroits affirment que la classe Integer dans Java est immuable, mais le code suivant:

Integer a=3;
Integer b=3;
a+=b;
System.out.println(a);

S'exécute sans problème en donnant le résultat (attendu) 6. Donc, effectivement, la valeur de a a changé. Cela ne signifie-t-il pas qu'Integer est mutable? Question secondaire et un peu décalée: "Les classes immuables n'ont pas besoin de constructeurs de copie". Quelqu'un veut expliquer pourquoi?

91
K.Steff

Immuable ne signifie pas que a ne peut jamais être égal à une autre valeur. Par exemple, String est immuable aussi, mais je peux toujours le faire:

String str = "hello";
// str equals "hello"
str = str + "world";
// now str equals "helloworld"

Alors que s'est-il passé là-bas? Puisque String est immuable, il est clair que str n'a pas été modifié. Mais cela équivaut maintenant à quelque chose de différent. Ceci est dû au fait que str est maintenant un objet complètement nouvellement instancié, tout comme votre Integer. Ainsi, la valeur de a ne mute pas, mais elle est remplacée par un nouvel objet, à savoir new Integer(6).

88
Travis Webb

a est une "référence" à un Integer (3), votre raccourci a+=b signifie vraiment faire ceci:

a = new Integer(3 + 3)

Donc non, les entiers ne sont pas mutables, mais les variables qui les pointent sont *.

* Il est possible d'avoir des variables immuables, elles sont désignées par le mot clé final, ce qui signifie que la référence ne peut pas changer.

final Integer a = 3;
final Integer b = 3;
a += b; // compile error, the variable `a` is immutable, too.
48
Mark Elliot

Vous pouvez déterminer que l'objet a été modifié à l'aide de System.identityHashCode() (un meilleur moyen consiste à utiliser un simple == cependant, il n’est pas aussi évident que la référence ait été modifiée plutôt que la valeur)

Integer a = 3;
System.out.println("before a +=3; a="+a+" id="+Integer.toHexString(System.identityHashCode(a)));
a += 3;
System.out.println("after a +=3; a="+a+" id="+Integer.toHexString(System.identityHashCode(a)));

empreintes

before a +=3; a=3 id=70f9f9d8
after a +=3; a=6 id=2b820dda

Vous pouvez voir que "l'id" sous-jacent de l'objet a a changé.

17
Peter Lawrey

A la question initiale posée,

Integer a=3;
Integer b=3;
a+=b;
System.out.println(a);

Integer est immuable, donc ce qui est arrivé ci-dessus est "a" a été remplacé par une nouvelle référence de valeur 6. La valeur initiale 3 reste sans référence dans la mémoire (elle n'a pas été modifiée), elle peut donc être récupérée.

Si cela arrive à une chaîne, elle restera dans le pool (dans l'espace PermGen) plus longtemps que les entiers, car elle s'attend à avoir des références.

10
Harsha

Oui Integer est immuable.

A est une référence qui pointe vers un objet. Lorsque vous exécutez un + = 3, cela réaffecte A à faire référence à un nouvel objet Integer, avec une valeur différente.

Vous n'avez jamais modifié l'objet d'origine, vous avez plutôt indiqué la référence à un autre objet.

Lisez à propos de la différence entre les objets et les références ici .

8
Andy

Immuable ne signifie pas que vous ne pouvez pas modifier la valeur d'une variable. Cela signifie simplement que toute nouvelle affectation crée un nouvel objet (lui attribue un nouvel emplacement mémoire), puis la valeur lui est affectée.

Pour comprendre cela par vous-même, effectuez une affectation d'entier dans une boucle (l'entier déclaré en dehors de la boucle) et examinez les objets vivants en mémoire.

La raison pour laquelle le constructeur de copie n'est pas nécessaire pour les objets immuables est du simple bon sens. Étant donné que chaque affectation crée un nouvel objet, le langage crée techniquement une copie, ce qui vous évite de créer une autre copie.

3

"Les classes immuables n'ont pas besoin de constructeurs de copie". Quelqu'un veut expliquer pourquoi?

La raison en est qu'il y a rarement le besoin de copier (ou même de copier) une instance d'une classe immuable. La copie de l'objet doit être "la même chose que" l'original, et si c'est le même, il ne devrait pas être nécessaire de le créer.

Il existe cependant quelques hypothèses sous-jacentes:

  • Cela suppose que votre application ne donne aucune signification à l'identité d'objet des instances de la classe.

  • Il suppose que la classe a surchargé equals et hashCode, de sorte qu'une copie d'une instance serait "la même chose que" l'original ... selon ces méthodes.

L'une ou l'autre de ces hypothèses pourrait être fausse, et cela pourrait justifier l'ajout d'un constructeur de copie.

2
Stephen C

Voilà comment je comprends immuable

int a=3;    
int b=a;
b=b+5;
System.out.println(a); //this returns 3
System.out.println(b); //this returns 8

Si int pouvait muter, "a" afficherait 8 mais pas parce qu'il est immuable, c'est pourquoi il en est 3. Votre exemple est simplement une nouvelle tâche.

1
ndheti

Je peux dire clairement qu'Integer (et d'autres de ses croyances comme Float, Short etc.) sont immuables par un simple exemple de code:

exemple de code

public class Test{
    public static void main(String... args){
        Integer i = 100;
        StringBuilder sb = new StringBuilder("Hi");
        Test c = new Test();
        c.doInteger(i);
        c.doStringBuilder(sb);
        System.out.println(sb.append(i)); //Expected result if Integer is mutable is Hi there 1000
    }

    private void doInteger(Integer i){
        i=1000;
    }

    private void doStringBuilder(StringBuilder sb){
        sb.append(" there");
    }

}

Résultat réel

Le résultat arrive à il Hi There 1 au lieu du résultat attendu (si sb et i sont des objets mutables) Hi There 10

Ceci montre que l'objet créé par i in main n'est pas modifié, alors que le sb est modifié.

Donc, StringBuilder a démontré un comportement mutable mais pas Integer.

Donc, Integer est immuable. donc prouvé

n autre code sans que Integer:

public class Test{
    public static void main(String... args){
        Integer i = 100;
        Test c = new Test();
        c.doInteger(i);
        System.out.println(i); //Expected result is 1000 in case Integer is mutable
    }

    private void doInteger(Integer i){
        i=1000;
    }


}
0
Ashutosh Nigam