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 ?
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 ?
Vous trouverez ci-dessous les dur les exigences d'un objet immuable.
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 .
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{}.
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 :) ).
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 ?
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.
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.
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 !
WRT #4 Comment la visibilité des constructeurs affecte-t-elle la mutabilité ? String est immuable mais possède plusieurs constructeurs publics.
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
?
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 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.
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.
0 votes
Existe-t-il un autre moyen d'initialiser les champs que le constructeur ? J'ai plus de 20 champs dans ma classe. Il est très difficile d'initialiser tous les champs en utilisant le constructeur, certains champs sont même facultatifs.