Comment créer des objets immuables en Java?
Quels objets devraient être appelés immuables?
Si j'ai cours avec tous les membres statiques, est-ce immuable?
Vous trouverez ci-dessous les exigences strictes d'un objet immuable.
final
mais que l'objet peut toujours être mutable. C'est-à-dire private final Date imStillMutable
). Vous devriez faire defensive copies
dans ces cas.Le raisonnement derrière la classe final
est très subtil et souvent négligé. Si ses utilisateurs finaux ne peuvent pas librement étendre votre classe, remplacez le comportement public
ou protected
, ajoutez des propriétés mutables, puis fournissez leur sous-classe en tant que substitut. En déclarant la classe final
, vous pouvez vous assurer que cela ne se produira pas.
Pour voir le problème en action, considérons 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épendance. Vous n'instanciez pas explicitement les choses et la référence à la super classe qui vous est donnée peut en fait être une sous-classe.
La conclusion est que pour faire des garanties sur l'immutabilité, vous devez marquer la classe comme final
. Ceci est traité en profondeur dans Java effectif de Joshua Bloch et est explicitement référencé dans la spécification du modèle modèle de mémoire Java .
Il suffit simplement d’ajouter des méthodes de mutateur public (setter) à la classe.
Les classes ne sont pas immuables, les objets le sont.
Immuable signifie: mon état visible public 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 à assurer la sécurité du fil
Si votre classe n'a que des membres statiques, les objets de cette classe sont immuables, car vous ne pouvez pas modifier l'état de cet objet (vous ne pouvez probablement pas le créer non plus :))
Pour rendre une classe immuable dans Java, vous pouvez noter les points suivants:
1. Ne fournissez pas de méthodes de définition pour modifier les valeurs des variables d'instance de la classe.
2. Déclarer la classe comme 'final' . Cela empêcherait toute autre classe de l'étendre et donc de remplacer toute méthode susceptible de modifier les valeurs de variable d'instance.
3. Déclarer les variables d'instance comme privé et final.
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 nécessaire.
Ces points devraient aider !!
Depuis Oracle site, comment créer des objets immuables en Java.
- Ne fournissez pas de méthodes "setter" - méthodes qui modifient des champs ou des objets référencés par des champs.
- Rendre tous les champs finaux et privés.
- N'autorisez pas les sous-classes à remplacer les méthodes. Le moyen le plus simple de procéder consiste à déclarer la classe finale. Une approche plus sophistiquée consiste à rendre le constructeur privé et à construire des instances dans les méthodes d'usine.
- Si les champs d'instance incluent des références à des objets mutables, n'autorisez pas ces objets à être modifiés:
JE. Ne fournissez pas de méthodes qui modifient les objets mutables.
II. Ne partagez pas les références aux objets mutables. Ne stockez jamais de références à des objets externes, mutables, transmis au constructeur; si nécessaire, créez des copies et stockez les références aux copies. De même, créez des copies de vos objets mutables internes lorsque cela est nécessaire pour éviter de renvoyer les originaux dans vos méthodes.
Minimiser la mutabilité
Une classe immuable est simplement une classe dont les instances ne peuvent pas être modifiées. Toutes les informations contenues dans chaque instance sont fournies lors de sa création et sont fixes pour la durée de vie de l'objet.
Classes immuables JDK: String, les classes primitives encadrées (classes wrapper), BigInteger et BigDecimal, etc.
Comment rendre une classe immuable?
Faites des copies défensives. Assure un accès exclusif à tous les composants mutables.
public List getList () {return Collections.unmodifiableList (list); <=== copie défensive du champ mutable avant de le renvoyer à l'appelant}
Si votre classe contient des champs faisant référence à des objets mutables, assurez-vous que les clients de la classe ne peuvent pas obtenir de références à ces objets. N'initialisez jamais un tel champ sur une référence d'objet fournie par le client ou ne renvoyez pas la référence d'objet à partir d'un accesseur.
import Java.util.Date;
public final class ImmutableClass {
public ImmutableClass(int id, String name, Date doj) {
this.id = id;
this.name = name;
this.doj = doj;
}
private final int id;
private final String name;
private final Date doj;
public int getId() {
return id;
}
public String getName() {
return name;
}
/**
* Date class is mutable so we need a little care here.
* We should not return the reference of original instance variable.
* Instead a new Date object, with content copied to it, should be returned.
* */
public Date getDoj() {
return new Date(doj.getTime()); // For mutable fields
}
}
import Java.util.Date;
public class TestImmutable {
public static void main(String[] args) {
String name = "raj";
int id = 1;
Date doj = new Date();
ImmutableClass class1 = new ImmutableClass(id, name, doj);
ImmutableClass class2 = new ImmutableClass(id, name, doj);
// every time will get a new reference for same object. Modification in reference will not affect the immutability because it is temporary reference.
Date date = class1.getDoj();
date.setTime(date.getTime()+122435);
System.out.println(class1.getDoj()==class2.getDoj());
}
}
Pour plus d'informations, voir mon blog:
http://javaexplorer03.blogspot.in/2015/07/minimize-mutability.html
Tout d'abord, vous savez pourquoi vous devez créer un objet immuable et quels sont les avantages d'un objet immuable.
Avantages d'un objet immuable
Accès simultané et multithreading Il est automatiquement thread-safe alors problème de synchronisation .... etc
Pas besoin de copie le constructeur Pas besoin d'implémentation de clone. La classe ne peut pas être override Rendre le champ en tant que privé et final Forcer 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 la construction de l'objet immuable.
s'il vous plaît voir 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();
}
}
Un objet immuable est un objet qui ne changera pas son état interne après la création. Ils sont très utiles dans les applications multithreads car ils peuvent être partagés entre les threads sans synchronisation.
1. N'ajoutez aucune méthode de définition
Si vous construisez un objet immuable, son état interne ne changera jamais. La tâche d'une méthode de définition consiste à modifier la valeur interne d'un champ, de sorte que vous ne pouvez pas l'ajouter.
2. Déclarer tous les champs final et privé
Un champ privé n'est pas visible de l'extérieur de la classe. Aucune modification manuelle ne peut donc y être appliquée.
Déclarer un champ final garantira que, s'il référence une valeur primitive, la valeur ne changera jamais s'il référence un objet, la référence ne peut pas être modifiée. Cela ne suffit pas pour garantir qu'un objet comportant uniquement des champs finaux privés ne soit pas mutable.
. Si un champ est un objet mutable, créez-en des copies défensives pour les méthodes getter
Nous avons vu précédemment que définir un champ final et private n'est pas suffisant car il est possible de changer son état interne. Pour résoudre ce problème, nous devons créer une copie défensive de ce champ et le renvoyer chaque fois qu'il est demandé.
4. Si un objet mutable passé au constructeur doit être affecté à un champ, créer une copie défensive de celui-ci
Le même problème se produit si vous détenez une référence transmise au constructeur car il est possible de la modifier. Ainsi, le fait de conserver une référence à un objet transmis au constructeur peut créer des objets mutables. Pour résoudre ce problème, il est nécessaire de créer une copie défensive du paramètre s'il s'agit d'objets mutables.
Notez que si un champ est une référence à un objet immuable, il n'est pas nécessaire de créer des copies défensives de celui-ci dans le constructeur et dans les méthodes de lecture, il suffit de définir le champ comme final et privé.
5. Ne pas autoriser les sous-classes à remplacer les méthodes
Si une sous-classe remplace une méthode, elle peut renvoyer la valeur d'origine d'un champ mutable au lieu d'une copie défensive de celle-ci.
Si vous suivez ces règles simples, vous pouvez librement partager vos objets immuables entre les threads car ils sont thread-safe!
Il n'y a pas de bien ou de mal, cela dépend de ce que vous préférez. Cela dépend de vos préférences et de ce que vous voulez réaliser (et être en mesure d'utiliser facilement les deux approches sans aliéner les fans inconditionnels d'un côté ou de l'autre est un saint graal que certaines langues recherchent).
Les quelques étapes suivantes doivent être prises en compte lorsque vous souhaitez qu'une classe soit immuable.
Jetons un coup d'oeil ce que nous avons tapé ci-dessus:
//ImmutableClass
package younus.attari;
public final class ImmutableExample {
private final String name;
private final String address;
public ImmutableExample(String name,String address){
this.name=name;
this.address=address;
}
public String getName() {
return name;
}
public String getAddress() {
return address;
}
}
//MainClass from where an ImmutableClass will be called
package younus.attari;
public class MainClass {
public static void main(String[] args) {
ImmutableExample example=new ImmutableExample("Muhammed", "Hyderabad");
System.out.println(example.getName());
}
}
un objet est appelé immuable si son état ne peut pas être changé une fois créé. L’un des moyens les plus simples de créer une classe immuable dans Java) consiste à définir tous ses champs comme étant définitifs. Si vous devez écrire une classe immuable comprenant des classes mutables telles que "Java.util.Date" Afin de préserver l’immuabilité dans de tels cas, il est conseillé de renvoyer une copie de l’objet original,
Les objets immuables sont les objets dont l'état ne peut plus être modifié une fois qu'ils ont été créés. Par exemple, la classe String est une classe immuable. Les objets immuables ne peuvent pas être modifiés, ils sont donc également sécurisés pour les threads lors d'une exécution simultanée.
Caractéristiques des classes immuables:
Clés pour écrire une classe immuable:
En plus de la réponse fournie par @ nsfyn55, les aspects suivants doivent également être pris en compte pour l’immuabilité des objets, qui sont d’importance première
Considérez les classes suivantes:
public final class ImmutableClass {
private final MutableClass mc;
public ImmutableClass(MutableClass mc) {
this.mc = mc;
}
public MutableClass getMutClass() {
return this.mc;
}
}
public class MutableClass {
private String name;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
public class MutabilityCheck {
public static void main(String[] args) {
MutableClass mc = new MutableClass();
mc.setName("Foo");
ImmutableClass iMC = new ImmutableClass(mc);
System.out.println(iMC.getMutClass().getName());
mc.setName("Bar");
System.out.println(iMC.getMutClass().getName());
}
}
Voici le résultat de MutabilityCheck:
Foo
Bar
Il est important de noter que,
Construction d'objets mutables sur un objet immuable (via le constructeur), soit en 'copie' ou 'cloing' en variables d'instance de l'immuable décrites par les modifications suivantes:
public final class ImmutableClass {
private final MutableClass mc;
public ImmutableClass(MutableClass mc) {
this.mc = new MutableClass(mc);
}
public MutableClass getMutClass() {
return this.mc;
}
}
public class MutableClass {
private String name;
public MutableClass() {
}
//copy constructor
public MutableClass(MutableClass mc) {
this.name = mc.getName();
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
n'assure toujours pas une immuabilité complète car ce qui suit est toujours valable à partir de la classe MutabilityCheck:
iMC.getMutClass().setName("Blaa");
Cependant, si vous exécutez MutabilityCheck avec les modifications apportées dans 1., le résultat sera:
Foo
Foo
Pour obtenir une immuabilité complète sur un objet, tous ses les objets dépendants doivent également être immuables