85 votes

Comment créer des objets immuables en Java ?

Comment créer des objets immuables en Java ?

Quels objets doivent être dits immuables ?

Si j'ai une classe avec tous les membres statiques, est-elle immuable ?

0 votes

Duplicata possible de Qu'entend-on par "immuable" ?

1 votes

La question liée ci-dessus n'est pas la même, mais les réponses à cette question devraient répondre à toutes vos interrogations.

0 votes

Si votre classe ne comporte que des membres statiques, elle est apatride (aucune instance n'a d'état individuel) et la question de la mutabilité ou de l'immuabilité devient sans objet.

90voto

nsfyn55 Points 4753

Vous trouverez ci-dessous les dur les exigences d'un objet immuable.

  1. Rendre la classe finale
  2. rendre tous les membres définitifs, les fixer explicitement, dans un bloc statique ou dans le constructeur.
  3. Rendre tous les membres privés
  4. Pas de méthodes qui modifient l'état
  5. Soyez extrêmement prudent pour limiter l'accès aux membres mutables (rappelez-vous que le champ peut être final mais l'objet peut toujours être mutable. ie private final Date imStillMutable ). Vous devez faire defensive copies dans ces cas.

Le raisonnement derrière la création de la classe final est très subtile et souvent négligée. Si elle n'est pas finale, les gens peuvent librement étendre votre classe, surcharger public o protected le comportement, ajouter des propriétés mutables, puis fournir leur sous-classe comme substitut. En déclarant la classe final vous pouvez vous assurer que cela n'arrivera pas.

Pour voir le problème en action, prenez l'exemple ci-dessous :

public class MyApp{

    /**
     * @param args
     */
    public static void main(String[] args){

        System.out.println("Hello World!");

        OhNoMutable mutable = new OhNoMutable(1, 2);
        ImSoImmutable immutable = mutable;

        /*
         * Ahhhh Prints out 3 just like I always wanted
         * and I can rely on this super immutable class 
         * never changing. So its thread safe and perfect
         */
        System.out.println(immutable.add());

        /* Some sneak programmer changes a mutable field on the subclass */
        mutable.field3=4;

        /*
         * Ahhh let me just print my immutable 
         * reference again because I can trust it 
         * so much.
         * 
         */
        System.out.println(immutable.add());

        /* Why is this buggy piece of crap printing 7 and not 3
           It couldn't have changed its IMMUTABLE!!!! 
         */
    }

}

/* This class adheres to all the principles of 
*  good immutable classes. All the members are private final
*  the add() method doesn't modify any state. This class is 
*  just a thing of beauty. Its only missing one thing
*  I didn't declare the class final. Let the chaos ensue
*/ 
public class ImSoImmutable{
    private final int field1;
    private final int field2;

    public ImSoImmutable(int field1, int field2){
        this.field1 = field1;
        this.field2 = field2;
    }

    public int add(){
        return field1+field2;
    }
}

/*
This class is the problem. The problem is the 
overridden method add(). Because it uses a mutable 
member it means that I can't  guarantee that all instances
of ImSoImmutable are actually immutable.
*/ 
public class OhNoMutable extends ImSoImmutable{   

    public int field3 = 0;

    public OhNoMutable(int field1, int field2){
        super(field1, field2);          
    }

    public int add(){
       return super.add()+field3;  
    }

}

En pratique, il est très courant de rencontrer le problème ci-dessus dans les environnements d'injection de dépendances. Vous n'instanciez pas explicitement les choses et la référence de la super classe qui vous est donnée peut en fait être une sous-classe.

La conclusion est que pour faire des garanties solides sur l'immuabilité, vous devez marquer la classe comme étant final . Ce sujet est traité en profondeur dans l'ouvrage de Joshua Bloch intitulé Java efficace et référencée explicitement dans la spécification de la Modèle de mémoire Java .

0 votes

Qu'en est-il de tous les membres statiques ?

1 votes

La classe n'a pas besoin d'être finale pour cela.

0 votes

Les membres statiques sont couverts par le numéro 2. Vous ne pouvez pas les définir dans le constructeur, vous devez donc les définir explicitement ou dans un bloc static{}.

14voto

Alexander Pogrebnyak Points 24964

Les classes ne sont pas immuables, les objets le sont.

Immuable signifie : mon état public visible ne peut pas changer après l'initialisation.

Les champs ne doivent pas nécessairement être déclarés finaux, bien que cela puisse aider énormément à garantir la sécurité des fils.

Si votre classe n'a que des membres statiques, alors les objets de cette classe sont immuables, car vous ne pouvez pas changer l'état de cet objet (vous ne pouvez probablement pas le créer non plus :) ).

3 votes

Rendre tous les champs statiques limite toutes les intsances à partager le même état, ce qui n'est pas vraiment utile.

14voto

BalusC Points 498232

Il suffit de ne pas ajouter de méthodes publiques de type mutateur (setter) à la classe.

0 votes

Qu'en est-il de tous les membres statiques ? La référence ou l'état de l'objet change-t-il pour ce type d'objets ?

7 votes

Cela n'a pas d'importance. Si vous ne pouvez pas les modifier de l'extérieur par une méthode quelconque, c'est immuable.

0 votes

On ne peut pas répondre à cette question car on ne sait pas ce que font les membres statiques ... bien sûr, ils peuvent modifier les champs privés. S'ils le font, la classe n'est pas imuable.

6voto

VishEnthusiast Points 21

Pour rendre une classe immuable en Java , vous pouvez prendre note des points suivants :

1. Ne fournissez pas de méthodes setter pour modifier les valeurs de l'une des variables d'instance de la classe.

2. Déclarez la classe comme final . Cela empêcherait toute autre classe de l'étendre et donc de surcharger une méthode de cette classe qui pourrait modifier les valeurs des variables d'instance.

3. Déclarer les variables d'instance comme privé et définitif .

4. Vous pouvez également déclarer le constructeur de la classe en tant que privé et ajoutez une méthode de fabrique pour créer une instance de la classe lorsque cela est nécessaire.

Ces points devraient vous aider !

3 votes

WRT #4 Comment la visibilité des constructeurs affecte-t-elle la mutabilité ? String est immuable mais possède plusieurs constructeurs publics.

0 votes

Comme l'a dit @Ryan, la même chose s'applique aux variables d'instance : pourquoi celles-ci devraient-elles être déclarées private ?

0 votes

Je ne sais pas pourquoi cette réponse a des votes positifs. Cette réponse est incomplète. Elle ne parle pas des objets mutables, ce qui est assez important pour être abordé. Veuillez lire l'explication de @nsfyn55 pour une meilleure compréhension.

2voto

J.B.Vala Points 33

Tout d'abord, vous devez savoir pourquoi vous devez créer un objet immuable, et quels sont les avantages de l'objet immuable.

Avantages d'un objet immuable

Concurrence et multithreading Il est automatiquement Thread-safe donc problème de synchronisation....etc

Pas besoin de constructeur de copie Pas besoin d'implémentation de clone. La classe ne peut pas être contourner Faites du champ un privé et définitif Force les appelants à construire un objet complètement en une seule étape, au lieu d'utiliser un constructeur sans argument.

Les objets immuables sont simplement des objets dont l'état signifie que les données de l'objet ne peuvent pas changer après que les objets immuables sont construits.

veuillez consulter le code ci-dessous.

public final class ImmutableReminder{
    private final Date remindingDate;

    public ImmutableReminder (Date remindingDate) {
        if(remindingDate.getTime() < System.currentTimeMillis()){
            throw new IllegalArgumentException("Can not set reminder" +
                    " for past time: " + remindingDate);
        }
        this.remindingDate = new Date(remindingDate.getTime());
    }

    public Date getRemindingDate() {
        return (Date) remindingDate.clone();
    }
}

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