415 votes

Qu’entend-on par immuable ?

Cela pourrait être la plus stupide question jamais posée, mais je pense que c’est une confusion totale pour un débutant. Peut quelqu'un clarifier ce que signifie immuable ? Pourquoi est une chaîne immuable ? Quels sont les avantages/inconvénients des objets immuables ? Pourquoi un objet mutable tels que StringBuilder être préférée au fil de chaîne et vice versa ? Un bel exemple (en Java) sera apprécié.

276voto

Douglas Leeder Points 29986

Immuable signifie qu'une fois que le constructeur d'un objet a terminé l'exécution de cette instance ne peuvent pas être modifiés.

Ceci est utile, car cela signifie que vous pouvez passer des références à l'objet, sans se soucier que quelqu'un d'autre va modifier son contenu. Surtout lorsqu'il s'agit de la simultanéité, il n'y a pas de verrouillage de problèmes avec des objets qui ne changent jamais

par exemple

class Foo
{
     private final String myvar;

     public Foo(final String initialValue)
     {
         this.myvar = initialValue;
     }

     public String getValue()
     {
         return this.myvar;
     }
}

Foo n'ont pas à s'inquiéter que l'appelant getValue() pouvez modifier le texte dans la chaîne.

Si vous imaginez une catégorie similaire à l' Foo, mais avec un StringBuilder plutôt qu'un String en tant que membre, vous pouvez voir qu'un appelant d' getValue() serait en mesure de modifier l' StringBuilder d'attribut d'un Foo de l'instance.

Edit:

Aussi méfiez-vous de les différents types de l'immuabilité que vous pourriez trouver: Eric Lippert a écrit un article de blog à ce sujet. Fondamentalement, vous pouvez avoir des objets dont l'interface est immuable, mais derrière les scènes réelles des mutables privé de l'état (et, par conséquent, ne peuvent pas être partagés en toute sécurité entre les threads).

82voto

Imagist Points 5348

Immuable objet est un objet où les champs internes (ou au moins, tous les champs internes qui influent sur son comportement externe) ne peut pas être modifié.

Il y a beaucoup d'avantages à cordes immuables:

Performance: Prendre de l'opération suivante:

String substring = fullstring.substring(x,y);

Le sous-jacent C pour la méthode substring() est probablement quelque chose comme ceci:

// Assume string is stored like this:
struct String { char* characters; unsigned int length; };

// Passing pointers because Java is pass-by-reference
struct String* substring(struct String* in, unsigned int begin, unsigned int end)
{
    struct String* out = malloc(sizeof(struct String));
    out->characters = in->characters + begin;
    out->length = end - begin;
    return out;
}

Notez qu' aucun des personnages doivent être copiés! Si la Chaîne de caractères de l'objet ont été mutable (les personnages peuvent changer plus tard) ensuite, vous devez copier tous les personnages, autrement les changements de caractères dans la chaîne serait le reflet de l'autre chaîne plus tard.

Concurrence: Si la structure interne d'un objet immuable est valide, il sera toujours valide. Il n'y a aucune chance que les différents threads peuvent créer un état non valide dans cet objet.

La collecte des ordures: Il est beaucoup plus facile pour le garbage collector pour prendre des décisions logiques sur des objets immuables.

Cependant, il ya aussi des inconvénients à l'immuabilité:

Performance: Attendez, j'ai pensé que vous avez dit de la performance a été à la hausse de l'immuabilité! Eh bien, il est parfois, mais pas toujours. Prenez le code suivant:

foo = foo.substring(0,4) + "a" + foo.substring(5);  // foo is a String
bar.replace(4,5,"a"); // bar is a StringBuilder

Les deux lignes à la fois remplacer le quatrième personnage avec la lettre "a". Non seulement est le deuxième morceau de code plus lisible, c'est plus rapide. Regardez comment vous auriez à faire le code sous-jacent pour les foo. Les sous-chaînes sont faciles, mais maintenant, parce qu'il y a déjà un caractère à l'espace de cinq et quelque chose d'autre pourrait être de référencement foo, vous ne pouvez pas le modifier, vous devez copier l'ensemble de la chaîne (bien sûr, certaines de ces fonctionnalités est abstrait dans des fonctions dans le réel C sous-jacente, mais le point ici est de montrer le code qui est exécuté en un seul endroit).

struct String* concatenate(struct String* first, struct String* second)
{
    struct String* new = malloc(sizeof(struct String));
    new->length = first->length + second->length;

    new->characters = malloc(new->length);

    int i;

    for(i = 0; i < first->length; i++)
        new->characters[i] = first->characters[i];

    for(; i - first->length < second->length; i++)
        new->characters[i] = second->characters[i - first->length];

    return new;
}

// The code that executes
struct String* astring;
char a = 'a';
astring->characters = &a;
astring->length = 1;
foo = concatenate(concatenate(slice(foo,0,4),astring),slice(foo,5,foo->length));

Notez que concaténer est appelée deux fois, ce qui signifie que l'ensemble de la chaîne doit être bouclé! Comparez cela à du code C pour l' bar fonctionnement:

bar->characters[4] = 'a';

La mutable opération de chaîne est évidemment beaucoup plus rapide.

En Conclusion: Dans la plupart des cas, vous voulez immuable de la chaîne. Mais si vous avez besoin de faire beaucoup de l'ajout et de l'insertion dans une chaîne de caractères, vous avez besoin de la mutabilité de la vitesse. Si vous voulez la sécurité de la simultanéité et de collecte des ordures prestations, avec elle, la clé est de garder vos objets mutables locale à une méthode:

// This will have awful performance if you don't use mutable strings
String join(String[] strings, String separator)
{
    StringBuilder mutable;
    boolean first = true;

    for(int i = 0; i < strings.length; i++)
    {
        if(!first) first = false;
        else mutable.append(separator);

        mutable.append(strings[i]);
    }

    return mutable.toString();
}

Depuis l' mutable objet est une référence locale, vous n'avez pas à vous soucier de la sécurité de la simultanéité (un seul thread jamais la touche). Et comme il n'est pas référencé nulle part ailleurs, il n'est alloué sur la pile, de sorte qu'il est libéré dès que l'appel de la fonction est terminée (vous n'avez pas à vous soucier de la collecte des ordures). Et vous obtenez tous les avantages de performance à la fois de la mutabilité et de l'immuabilité.

24voto

Jason Coco Points 52303

Des objets immuables sont des objets qui ne peuvent pas être modifiée par programmation. Ils sont particulièrement bons pour les environnements multi-threads ou d'autres environnements où plus d'un processus est en mesure de modifier (muter) les valeurs dans un objet.

Juste pour préciser, toutefois, StringBuilder est en fait un objet mutable, pas immuable. Régulièrement java String est immuable (ce qui signifie qu'une fois qu'il est créé, vous ne pouvez pas modifier le sous-jacent de chaîne sans modification de l'objet).

Par exemple, disons que j'ai une classe appelée ColoredString qui a une valeur de Chaîne et d'une Chaîne de couleur:

public class ColoredString {

    private String color;
    private String string;

    public ColoredString(String color, String string) {
    	this.color  = color;
    	this.string = string;
    }

    public String getColor()  { return this.color;  }
    public String getString() { return this.string; }

    public void setColor(String newColor) {
    	this.color = newColor;
    }

}

Dans cet exemple, le ColoredString est dit être mutable parce que vous pouvez modifier (muter) l'une de ses principales propriétés, sans création d'une nouvelle ColoredString classe. La raison pour laquelle cela peut être mauvaise, c'est, par exemple, disons que vous avez une application graphique qui a plusieurs threads et que vous utilisez ColoredStrings imprimer les données de la fenêtre. Si vous avez une instance de ColoredString qui a été créé comme

new ColoredString("Blue", "This is a blue string!");

Alors on s'attend à la chaîne pour être toujours "Bleu". Si un autre thread, cependant, se saisit de cette instance et a appelé

blueString.setColor("Red");

Vous tout à coup, et sans doute de façon inattendue, ont maintenant un "Rouge" de la chaîne lorsque vous voulait un "Bleu". De ce fait, des objets immuables sont presque toujours préféré lors du passage des instances d'objets autour. Lorsque vous avez un cas où mutable objets sont vraiment nécessaires, puis vous le feriez habituellement la garde de l'objet en ne faisant que des copies de votre domaine spécifique de contrôle.

Pour résumer, en Java, java.lang.String est un objet immuable (il ne peut pas être changé une fois qu'il est créé) et java.lang.StringBuilder est un objet mutable parce qu'il peut être modifié sans la création d'une nouvelle instance.

16voto

Georgy Bolyuba Points 3932

"immuable" signifie que vous ne pouvez pas changer la valeur. Si vous avez une instance de la classe String, n'importe quelle méthode vous appeler qui semble modifier la valeur, va en fait créer une autre Chaîne.

String foo = "Hello";
foo.substring(3);
<-- foo here still has the same value "Hello"

Pour conserver les modifications que vous devriez faire quelque chose comme ceci foo = foo.sustring(3);

Immuable vs mutable peut être drôle quand vous travaillez avec les collections. Pensez à ce qui va vous arriver si vous utilisez mutable objet comme une clé pour la carte et ensuite modifier la valeur (astuce: pensez à d'égal à égal et hasCode).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X