web-dev-qa-db-fra.com

Faire un objet Java immuable

Mon objectif est de rendre un objet Java immuable. J'ai une classe Student. Je l'ai codé de la manière suivante pour obtenir l'immutabilité:

public final class Student {

private String name;
private String age;

public Student(String name, String age) {
    this.name = name;
    this.age = age;
}

public String getName() {
    return name;
}

public String getAge() {
    return age;
}

}

Ma question est la suivante: quel est le meilleur moyen d’atteindre l’immuabilité de la classe Student

62

Votre classe n'est pas immuable à proprement parler, elle n'est qu'immuable. Pour le rendre immuable, vous devez utiliser final:

private final String name;
private final String age;

Bien que la différence puisse sembler subtile, elle peut faire une différence significative dans un contexte multi-threadé . Une classe immuable est intrinsèquement thread-safe, une classe effectivement immuable est thread-safe uniquement si elle est publiée en toute sécurité.

66
assylias

Il y a peu de choses que vous devez considérer pour faire une classe immuable:

  • Faites votre classe final - Vous avez déjà
  • Faites tous les champs private et final - Apportez les modifications appropriées dans votre code
  • Ne fournissez aucune méthode qui change l'état de votre instance.
  • Si vous avez des champs mutables dans votre classe, tels que List ou Date, les rendre final ne suffira pas. Vous devriez renvoyer une copie défensive à partir de leur getters, afin que leur état ne soit pas muté par les méthodes appelantes.

Pour le 4ème point, supposons que vous ayez un champ Date dans votre classe, alors le getter pour ce champ devrait ressembler à ceci:

public Date getDate() {
    return new Date(this.date.getTime());
}

Faire une copie défensive peut devenir un casse-tête lorsque votre champ mutable comprend lui-même un champ mutable, et que celui-ci peut contenir un autre champ mutable. Dans ce cas, vous devrez faire une copie de chacun d'eux de manière itérative. Nous nommons cette copie itérative de champs mutables comme Deep Copy .

La mise en œuvre de la copie en profondeur par vous-même peut s'avérer fastidieuse. Mais, en gardant cette question à part, vous devriez revoir votre conception de classe, une fois que vous vous retrouvez dans l’obligation de faire une copie défensive en profondeur.

56
Rohit Jain
  1. Déclarez la classe comme finale afin qu’elle ne puisse pas être étendue.
  2. Rendre tous les champs privés afin que l'accès direct ne soit pas autorisé.
  3. Ne fournissez pas de méthodes de définition pour les variables
  4. Définissez tous les champs mutables comme finaux afin que leur valeur ne puisse être affectée qu’une fois.
  5. Initialise tous les champs via un constructeur effectuant une copie en profondeur.
  6. Effectuez un clonage d'objets dans les méthodes d'accesseur en lecture pour renvoyer une copie plutôt que de renvoyer la référence d'objet réelle. 

la source

4
Premraj

Avec le mot clé final:

private final String name;
private final String age;
3
Adam Stelmaszczyk

Rendre les variables privées et aucune méthode de définition fonctionnera pour les types de données primitifs. Si ma classe a une collection d'objets?

Rendre toute classe immuable avec objet de collection?

Ecrivez votre propre objet de collection avec une classe de collecte et suivez les variables privées sans méthode de définition ou retourne un objet clone de votre objet collection.

public final class Student {

private StudentList names;//Which is extended from arraylist

public Student() {
names = DAO.getNamesList()//Which will return All Student names from Database  its upto you how you want to implement.
}

public StudentList getStudentList(){
return names;//you need to implement your own methods in StudentList class to iterate your arraylist; or you can return Enumeration object.
}

public Enumeration getStudentNamesIterator(
Enumeration e = Collections.enumeration(names);
return e;
}

public class StudentList extends ArrayList {

}
3
user4485029

C’est bien, mais je ferais aussi les champs final.

De plus, je ferais de l’âge une variable int ou double plutôt qu’une chaîne.

2
Peter Lawrey

Développer un peu la réponse.

final n'est pas la même chose que Immutable mais vous pouvez utiliser final pour rendre certaines choses immuables si vous l'utilisez de certaines manières.

Certains types sont immuables, en ce sens qu'ils représentent des valeurs immuables plutôt que des objets d'état changeant. Les chaînes, les nombres, etc. sont immuables. À la fin, nos objets se limitent généralement à des structures de données, référençant éventuellement des valeurs immuables, mais nous les modifions en affectant de nouvelles valeurs aux mêmes noms de champs.

Donc, pour rendre quelque chose de vraiment immuable, vous devez vous assurer que la version finale est utilisée jusqu'au bout, jusqu'à atteindre chaque champ atteignant chaque valeur à la base de votre arbre de composition. Sinon, quelque chose pourrait changer de dessous votre objet et ce n'est pas vraiment totalement immuable.

2
Chris Travers

Votre exemple est déjà un objet immuable, car les champs de la classe Student ne peuvent être définis que lors de l'initialisation d'instance.

Pour rendre un objet immuable, vous devez suivre ces étapes:

  1. N'utilisez aucune méthode pouvant modifier les champs de votre classe. Par exemple, n'utilisez pas de Setters.
  2. Évitez d'utiliser des champs publics non finaux. Si vos champs sont publics, vous devez les déclarer comme final et les initialiser dans le constructeur ou directement dans la ligne de déclaration.
2
Eldar Agalarov

Il est trop tard pour répondre, mais cela pourrait peut-être aider d'autres peuples qui ont cette question. 

  1. L'état de l'objet immuable ne peut pas être modifié après la construction, toute modification doit aboutir à un nouvel objet immuable.
  2. Tous les champs de la classe Immutable doivent être finaux.
  3. L'objet doit être correctement construit, c'est-à-dire que la référence de l'objet ne doit pas fuir pendant le processus de construction.
  4. L'objet doit être final afin de restreindre la sous-classe pour modifier l'immutabilité de la classe parente.

Je pense que ce lien aide davantage Lisez plus: http://javarevisited.blogspot.com/2013/03/how-to-create-immutable-class-object-Java-example-tutorial.html#ixzz40VDQDDL1

1
Yirga

C'est déjà immuable - vous ne pouvez pas changer le contenu une fois que vous l'avez initialisé, car vous n'avez pas encore créé de paramètres. Vous pouvez ajouter des mots clés finaux aux variables.

0
Nick C

Définir toutes les variables en tant que final et lors de la définition d'un champ, le rendre ainsi renvoyer la référence au nouvel objet Student avec la nouvelle valeur définie, comme dans String.

0
dev-null

Vous pouvez simplement suivre les directives présentées dans cet exemple (premier résultat dans Google): http://www.javapractices.com/topic/TopicAction.do?Id=29

0
JPetric

Voici quelques règles permettant de rendre une classe immuable en Java: 1. L'état de l'objet immuable ne peut pas être modifié après la construction, toute modification doit aboutir à un nouvel objet immuable . 2. Tous les champs de la classe Immutable doivent être définitifs . 3. L'objet doit être correctement construit, c'est-à-dire que la référence de l'objet ne doit pas fuir pendant le processus de construction . 4. L'objet doit être final afin de restreindre la sous-classe pour modifier l'immutabilité de la classe parente.

Exemple:

public final class Contacts {

private final String name;
private final String mobile;

public Contacts(String name, String mobile) {
    this.name = name;
    this.mobile = mobile;
}

public String getName(){
    return name;
}

public String getMobile(){
    return mobile;
}

}

Référez-vous à ce lien: http://javarevisited.blogspot.in/2013/03/how-to-create-immutable-class-object-Java-example-tutorial.html

0
Vijay Bhatt

Selon Stratégie de définition des objets immuables

  1. Ne fournissez pas de méthodes "setter" - des méthodes qui modifient des champs ou des objets référencés par des champs.

  2. Définissez tous les champs final et private.

  3. N'autorisez pas les sous-classes à remplacer les méthodes. Le moyen le plus simple consiste à déclarer la classe en tant que final.

    a. Une approche plus sophistiquée consiste à rendre la constructor privée et à construire des instances dans les méthodes d'usine.

  4. Si les champs d'instance incluent des références à des objets mutables, n'autorisez pas ces objets à être modifiés:

    a. Ne fournissez pas de méthodes qui modifient les objets mutables.

    b. 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 si nécessaire pour éviter de renvoyer les originaux dans vos méthodes.

0
YourAboutMeIsBlank