Wie erstelle ich unveränderliche Objekte in Java?


83

Wie erstelle ich unveränderliche Objekte in Java?

Welche Objekte sollten als unveränderlich bezeichnet werden?

Wenn ich eine Klasse mit allen statischen Mitgliedern habe, ist sie unveränderlich?



1
Die oben verlinkte Frage ist nicht dieselbe, aber die Antworten auf diese Frage sollten alle Ihre Fragen beantworten.
Joachim Sauer

Wenn Ihre Klasse nur aus statischen Mitgliedern besteht, ist sie zustandslos (keine Instanz hat einen individuellen Status) und die Frage nach veränderlich oder unveränderlich wird strittig.
Sebastian Redl

Gibt es eine andere Möglichkeit, andere Felder als den Konstruktor zu initialisieren? Ich habe mehr als 20 Felder in meiner Klasse. Es ist sehr schwierig, alle Felder mit dem Konstruktor zu initialisieren, einige Felder sind sogar optional.
Nikhil Mishra

Antworten:


87

Nachfolgend sind die harten Anforderungen an ein unveränderliches Objekt aufgeführt.

  1. Mach die Klasse endgültig
  2. Machen Sie alle Mitglieder endgültig, setzen Sie sie explizit, in einem statischen Block oder im Konstruktor
  3. Machen Sie alle Mitglieder privat
  4. Keine Methoden, die den Status ändern
  5. Achten Sie äußerst darauf, den Zugriff auf veränderbare Mitglieder zu beschränken (denken Sie daran, dass das Feld möglicherweise veränderbar ist final, das Objekt jedoch weiterhin veränderbar sein kann private final Date imStillMutable). Sie sollten defensive copiesin diesen Fällen machen.

Die Gründe für die Erstellung der Klasse finalsind sehr subtil und werden oft übersehen. Wenn es nicht endgültig ist, können Personen Ihre Klasse frei erweitern, überschreiben publicoder protectedverhalten, veränderbare Eigenschaften hinzufügen und dann ihre Unterklasse als Ersatz angeben. Indem Sie die Klasse deklarieren final, können Sie sicherstellen, dass dies nicht geschieht.

Um das Problem in Aktion zu sehen, betrachten Sie das folgende Beispiel:

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;  
    }

}

In der Praxis tritt das obige Problem häufig in Umgebungen mit Abhängigkeitsinjektion auf. Sie instanziieren Dinge nicht explizit und die Superklassenreferenz, die Sie erhalten, kann tatsächlich eine Unterklasse sein.

Um harte Garantien für die Unveränderlichkeit zu geben, muss die Klasse als markiert werden final. Dies wird in Joshua Blochs Effective Java ausführlich behandelt und in der Spezifikation für das Java-Speichermodell explizit erwähnt .


Was ist mit allen statischen Mitgliedern?
Neel Salpe

1
Die Klasse muss dafür nicht endgültig sein.
Angel O'Sphere

12
@Nilesh: Unveränderlichkeit ist die Eigenschaft von Instanzen . Statische Mitglieder beziehen sich normalerweise nicht auf eine einzelne Instanz, daher kommen sie hier nicht ins Spiel.
Joachim Sauer

4
Joshua Blochs Punkt 15 zur Unveränderlichkeit - Keine Methoden, die den Status ändern. Alle Felder endgültig. Alle Felder privat. Stellen Sie sicher, dass die Klasse nicht erweitert werden kann. Stellen Sie den exklusiven Zugriff auf veränderbare Komponenten sicher.
nsfyn55

2
@Jaochim - Sie sind absolut Teil der Gleichung - Nehmen Sie das obige Beispiel, wenn ich ein veränderbares statisches Element hinzufüge und es in der Add-Funktion von ImSoImmutable verwende. Sie haben das gleiche Problem. Wenn eine Klasse unveränderlich ist, müssen alle Aspekte unveränderlich sein.
nsfyn55

14

Fügen Sie der Klasse nur keine öffentlichen Mutator-Methoden (Setter-Methoden) hinzu.


Was ist mit allen statischen Mitgliedern? Ändert sich die Referenz oder der Objektstatus für einen solchen Objekttyp?
Neel Salpe

7
Ist egal. Wenn Sie sie durch eine Methode nicht extern ändern können, ist sie unveränderlich.
BalusC

Das kann nicht beantwortet werden, da wir nicht wissen, was die statischen Mitglieder tun ... oder wenn sie private Felder ändern könnten. Wenn sie das tun, ist die Klasse nicht nachahmbar.
Angel O'Sphere

Und der Klassenstandardkonstruktor sollte sein privateoder die Klasse sollte sein final. Nur um Vererbung zu vermeiden. Weil die Vererbung die Kapselung verletzt.
Talha Ahmed Khan

Wie wäre es, wenn Sie ein veränderliches Objekt, z. B. List, an das unveränderliche Objekt übergeben und es dann von außen ändern? Dies ist möglich und sollte durch die Verwendung defensiver Kopien während der Objekterstellung
behoben werden

14

Klassen sind nicht unveränderlich, Objekte sind.

Unveränderlich bedeutet: Mein öffentlich sichtbarer Zustand kann sich nach der Initialisierung nicht ändern.

Felder müssen nicht als endgültig deklariert werden, obwohl dies enorm zur Gewährleistung der Gewindesicherheit beitragen kann

Wenn Ihre Klasse nur statische Elemente hat, sind Objekte dieser Klasse unveränderlich, da Sie den Status dieses Objekts nicht ändern können (wahrscheinlich können Sie es auch nicht erstellen :))


3
Wenn Sie alle Felder statisch machen, werden alle Inttsanzen begrenzt, um denselben Status zu teilen, was nicht wirklich nützlich ist.
Aviad

6

Um eine Klasse in Java unveränderlich zu machen, können Sie die folgenden Punkte beachten:

1. Stellen Sie keine Setter-Methoden bereit, um die Werte einer der Instanzvariablen der Klasse zu ändern.

2. Deklarieren Sie die Klasse als 'final' . Dies würde verhindern, dass eine andere Klasse sie erweitert und somit eine Methode überschreibt, die Instanzvariablenwerte ändern könnte.

3. Deklarieren Sie die Instanzvariablen als privat und endgültig .

4. Sie können den Konstruktor der Klasse auch als privat deklarieren und bei Bedarf eine Factory-Methode hinzufügen, um eine Instanz der Klasse zu erstellen.

Diese Punkte sollten helfen !!


3
WRT # 4 Wie wirkt sich die Sichtbarkeit des Konstruktors auf die Mutabilität aus? String ist unveränderlich, hat aber mehrere öffentliche Konstruktoren.
Ryan

Wie @Ryan sagte, gilt das Gleiche für Instanzvariablen: Warum sollten diese deklariert werden private?
MC Emperor

Ich bin mir nicht sicher, warum diese Antwort positiv bewertet wurde. Diese Antwort ist unvollständig. Es geht nicht um veränderbare Objekte, was irgendwie wichtig ist, angesprochen zu werden. Bitte lesen Sie die Erklärung von @ nsfyn55 zum besseren Verständnis.
Ketan R

4

Von Oracle - Website, wie unveränderliche Objekte in Java erstellen.

  1. Stellen Sie keine "Setter" -Methoden bereit - Methoden, die Felder oder Objekte ändern, auf die Felder verweisen.
  2. Machen Sie alle Felder endgültig und privat.
  3. Unterklassen dürfen Methoden nicht überschreiben. Der einfachste Weg, dies zu tun, besteht darin, die Klasse als endgültig zu deklarieren. Ein komplexerer Ansatz besteht darin, den Konstruktor privat zu machen und Instanzen in Factory-Methoden zu konstruieren.
  4. Wenn die Instanzfelder Verweise auf veränderbare Objekte enthalten, dürfen diese Objekte nicht geändert werden:
    I. Geben Sie keine Methoden an, mit denen die veränderlichen Objekte geändert werden.
    II. Teilen Sie keine Verweise auf die veränderlichen Objekte. Speichern Sie niemals Verweise auf externe, veränderbare Objekte, die an den Konstruktor übergeben werden. Erstellen Sie gegebenenfalls Kopien und speichern Sie Verweise auf die Kopien. Erstellen Sie bei Bedarf Kopien Ihrer internen veränderlichen Objekte, um zu vermeiden, dass die Originale in Ihren Methoden zurückgegeben werden.

3

Ein unveränderliches Objekt ist ein Objekt, das seinen internen Status nach der Erstellung nicht ändert. Sie sind in Multithread-Anwendungen sehr nützlich, da sie ohne Synchronisierung von Threads gemeinsam genutzt werden können.

Um ein unveränderliches Objekt zu erstellen, müssen Sie einige einfache Regeln befolgen:

1. Fügen Sie keine Setter-Methode hinzu

Wenn Sie ein unveränderliches Objekt erstellen, ändert sich sein interner Status niemals. Die Aufgabe einer Setter-Methode besteht darin, den internen Wert eines Felds so zu ändern, dass Sie ihn nicht hinzufügen können.

2. Deklarieren Sie alle Felder als endgültig und privat

Ein privates Feld ist von außerhalb der Klasse nicht sichtbar, sodass keine manuellen Änderungen darauf angewendet werden können.

Wenn Sie ein Feld final deklarieren, wird garantiert, dass sich der Wert niemals ändert, wenn er auf einen primitiven Wert verweist, wenn er auf ein Objekt verweist. Die Referenz kann nicht geändert werden. Dies reicht nicht aus, um sicherzustellen, dass ein Objekt mit nur privaten Endfeldern nicht veränderbar ist.

3. Wenn ein Feld ein veränderbares Objekt ist, erstellen Sie defensive Kopien davon für Getter-Methoden

Wir haben zuvor gesehen, dass die Definition eines Feldes final und private nicht ausreicht, da es möglich ist, seinen internen Status zu ändern. Um dieses Problem zu lösen, müssen wir eine defensive Kopie dieses Feldes erstellen und dieses Feld jedes Mal zurückgeben, wenn es angefordert wird.

4. Wenn ein an den Konstruktor übergebenes veränderbares Objekt einem Feld zugewiesen werden muss, erstellen Sie eine defensive Kopie davon

Das gleiche Problem tritt auf, wenn Sie eine an den Konstruktor übergebene Referenz enthalten, da diese geändert werden kann. Wenn Sie also einen Verweis auf ein an den Konstruktor übergebenes Objekt halten, können veränderbare Objekte erstellt werden. Um dieses Problem zu lösen, muss eine defensive Kopie des Parameters erstellt werden, wenn es sich um veränderbare Objekte handelt.

Beachten Sie, dass es nicht ausreicht, das Feld als endgültig und privat zu definieren , wenn ein Feld eine Referenz auf ein unveränderliches Objekt ist, um defensive Konstruktionen davon im Konstruktor und in den Getter-Methoden zu erstellen.

5. Unterklassen dürfen Methoden nicht überschreiben

Wenn eine Unterklasse eine Methode überschreibt, kann sie den ursprünglichen Wert eines veränderlichen Feldes anstelle einer defensiven Kopie davon zurückgeben.

Um dieses Problem zu lösen, können Sie einen der folgenden Schritte ausführen:

  1. Deklarieren Sie die unveränderliche Klasse als endgültig, damit sie nicht erweitert werden kann
  2. Deklarieren Sie alle Methoden des unveränderlichen Klassenfinales, damit sie nicht überschrieben werden können
  3. Erstellen Sie einen privaten Konstruktor und eine Factory, um Instanzen der unveränderlichen Klasse zu erstellen, da eine Klasse mit privaten Konstruktoren nicht erweitert werden kann

Wenn Sie diese einfachen Regeln befolgen, können Sie Ihre unveränderlichen Objekte frei zwischen Threads teilen, da diese threadsicher sind!

Im Folgenden sind einige bemerkenswerte Punkte aufgeführt:

  • Unveränderliche Objekte machen das Leben in vielen Fällen tatsächlich einfacher. Sie eignen sich insbesondere für Werttypen, bei denen Objekte keine Identität haben, sodass sie leicht ersetzt werden können, und sie können die gleichzeitige Programmierung sicherer und sauberer machen (die meisten der notorisch schwer zu findenden Parallelitätsfehler werden letztendlich durch einen veränderlichen Status verursacht, der zwischen ihnen geteilt wird Fäden). Bei großen und / oder komplexen Objekten kann das Erstellen einer neuen Kopie des Objekts für jede einzelne Änderung jedoch sehr kostspielig und / oder langwierig sein . Und für Objekte mit einer bestimmten Identität ist das Ändern vorhandener Objekte viel einfacher und intuitiver als das Erstellen einer neuen, modifizierten Kopie davon.
  • Es gibt einige Dinge, die Sie mit unveränderlichen Objekten einfach nicht tun können, z. B. bidirektionale Beziehungen . Sobald Sie einen Zuordnungswert für ein Objekt festgelegt haben, ändert sich dessen Identität. Sie legen also den neuen Wert für das andere Objekt fest und dieser ändert sich ebenfalls. Das Problem ist, dass die Referenz des ersten Objekts nicht mehr gültig ist, da eine neue Instanz erstellt wurde, um das Objekt mit der Referenz darzustellen. Eine Fortsetzung würde nur zu unendlichen Regressionen führen.
  • Um einen binären Suchbaum zu implementieren , müssen Sie jedes Mal einen neuen Baum zurückgeben: Ihr neuer Baum musste eine Kopie jedes Knotens erstellen, der geändert wurde (die nicht geänderten Zweige werden gemeinsam genutzt). Für Ihre Einfügefunktion ist das nicht schlecht, aber für mich wurden die Dinge ziemlich ineffizient, als ich anfing, an Löschen und Neuausgleichen zu arbeiten.
  • Hibernate und JPA schreiben im Wesentlichen vor, dass Ihr System veränderbare Objekte verwendet, da die gesamte Voraussetzung darin besteht, dass sie Änderungen an Ihren Datenobjekten erkennen und speichern.
  • Abhängig von der Sprache kann ein Compiler beim Umgang mit unveränderlichen Daten eine Reihe von Optimierungen vornehmen, da er weiß, dass sich die Daten niemals ändern werden. Alle möglichen Dinge werden übersprungen, was Ihnen enorme Leistungsvorteile bietet.
  • Wenn Sie sich andere bekannte JVM-Sprachen ( Scala, Clojure ) ansehen , werden veränderbare Objekte selten im Code angezeigt. Deshalb werden sie in Szenarien verwendet, in denen Single-Threading nicht ausreicht.

Es gibt kein Richtig oder Falsch, es kommt nur darauf an, was Sie bevorzugen. Es hängt nur von Ihren Vorlieben ab und davon, was Sie erreichen möchten (und beide Ansätze problemlos anwenden zu können, ohne eingefleischte Fans der einen oder anderen Seite zu entfremden, ist ein heiliger Gral, nach dem einige Sprachen suchen).


2
  • Stellen Sie keine "Setter" -Methoden bereit - Methoden, die Felder oder Objekte ändern, auf die Felder verweisen.
  • Machen Sie alle Felder endgültig und privat.
  • Unterklassen dürfen Methoden nicht überschreiben. Der einfachste Weg, dies zu tun, besteht darin, die Klasse als endgültig zu deklarieren. Ein komplexerer Ansatz besteht darin, den Konstruktor privat zu machen und Instanzen in Factory-Methoden zu konstruieren.
  • Wenn die Instanzfelder Verweise auf veränderbare Objekte enthalten, dürfen diese Objekte nicht geändert werden:
    • Stellen Sie keine Methoden bereit, die die veränderlichen Objekte ändern.
    • Teilen Sie keine Verweise auf die veränderlichen Objekte. Speichern Sie niemals Verweise auf externe, veränderbare Objekte, die an den Konstruktor übergeben werden. Erstellen Sie gegebenenfalls Kopien und speichern Sie Verweise auf die Kopien. Erstellen Sie bei Bedarf Kopien Ihrer internen veränderlichen Objekte, um zu vermeiden, dass die Originale in Ihren Methoden zurückgegeben werden.

2

Zunächst wissen Sie, warum Sie ein unveränderliches Objekt erstellen müssen und welche Vorteile ein unveränderliches Objekt bietet.

Vorteile eines unveränderlichen Objekts

Parallelität und Multithreading Es ist automatisch threadsicher, so dass Synchronisationsprobleme auftreten ... usw.

Sie brauchen nicht zu Konstruktor kopieren nicht brauchen , um die Umsetzung von Klon. Klasse kann nicht überschrieben werden Machen Sie das Feld als privaten und endgültigen Aufrufer, ein Objekt vollständig in einem einzigen Schritt zu erstellen , anstatt einen Konstruktor ohne Argumente zu verwenden

Unveränderliche Objekte sind einfach Objekte, deren Status bedeutet, dass sich die Daten des Objekts nicht ändern können, nachdem das unveränderliche Objekt erstellt wurde.

Bitte beachten Sie den folgenden Code.

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();
    }
}

2

Mutabilität minimieren

Eine unveränderliche Klasse ist einfach eine Klasse, deren Instanzen nicht geändert werden können. Alle in jeder Instanz enthaltenen Informationen werden beim Erstellen bereitgestellt und sind für die Lebensdauer des Objekts festgelegt.

Unveränderliche JDK-Klassen: String, die Boxed-Primitive-Klassen (Wrapper-Klassen), BigInteger und BigDecimal usw.

Wie macht man eine Klasse unveränderlich?

  1. Geben Sie keine Methoden an, die den Status des Objekts ändern (sogenannte Mutatoren).
  2. Stellen Sie sicher, dass die Klasse nicht erweitert werden kann.
  3. Machen Sie alle Felder endgültig.
  4. Machen Sie alle Felder privat. Dies verhindert, dass Clients Zugriff auf veränderbare Objekte erhalten, auf die durch Felder verwiesen wird, und diese Objekte direkt ändern.
  5. Machen Sie defensive Kopien. Stellen Sie den exklusiven Zugriff auf veränderbare Komponenten sicher.

    öffentliche Liste getList () {return Collections.unmodizableList (Liste); <=== defensive Kopie des veränderlichen Feldes, bevor es an den Aufrufer zurückgegeben wird}

Wenn Ihre Klasse Felder enthält, die auf veränderbare Objekte verweisen, stellen Sie sicher, dass Clients der Klasse keine Verweise auf diese Objekte erhalten können. Initialisieren Sie ein solches Feld niemals mit einer vom Client bereitgestellten Objektreferenz oder geben Sie die Objektreferenz von einem Accessor zurück.

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());
       }
}

Weitere Informationen finden Sie in meinem Blog:
http://javaexplorer03.blogspot.in/2015/07/minimize-mutability.html


@Pang gibt es eine andere Möglichkeit, andere Felder als den Konstruktor zu initialisieren. Ich habe mehr als 20 Felder in meiner Klasse. Es ist sehr schwierig, alle Felder mit dem Konstruktor zu initialisieren, einige Felder sind sogar optional.
Nikhil Mishra

1
@NikhilMishra, Sie können das Builder-Entwurfsmuster verwenden, um Variablen während der Objektkonstruktion zu initialisieren. Sie können obligatorische Variablen, die im Konstruktor festgelegt werden sollen, und verbleibende optionale Variablen, die mithilfe der Setter-Methoden festgelegt werden sollen, beibehalten. Aber genau genommen werden Sie auf diese Weise keine True Immutable-Klasse erstellen.
sunny_dev

1

Ein Objekt wird als unveränderlich bezeichnet, wenn sein Status nach dem Erstellen nicht mehr geändert werden kann. Eine der einfachsten Möglichkeiten, unveränderliche Klassen in Java zu erstellen, besteht darin, alle Felder als endgültig festzulegen. Wenn Sie unveränderliche Klassen schreiben müssen, die veränderbare Klassen wie "java.util.Date" enthalten. Um die Unveränderlichkeit in solchen Fällen zu bewahren, wird empfohlen, eine Kopie des Originalobjekts zurückzugeben.


Es ist nicht ratsam, eine Kopie zurückzusenden, es ist notwendig. Es ist aber auch notwendig, dass im Konstruktor eine defensive Kopie erstellt wird. Andernfalls kann das Objekt hinter den Kulissen geändert werden.
Ryan

1

Unveränderliche Objekte sind Objekte, deren Status nach ihrer Erstellung nicht mehr geändert werden kann. Beispielsweise ist die String-Klasse eine unveränderliche Klasse. Unveränderliche Objekte können nicht geändert werden, sodass sie bei gleichzeitiger Ausführung auch threadsicher sind.

Merkmale unveränderlicher Klassen:

  • einfach zu konstruieren
  • automatisch threadsicher
  • Ein guter Kandidat für Kartenschlüssel und Festlegen, da sich ihr interner Status während der Verarbeitung nicht ändern würde
  • Klon muss nicht implementiert werden, da sie immer den gleichen Status darstellen

Schlüssel zum Schreiben einer unveränderlichen Klasse:

  • Stellen Sie sicher, dass die Klasse nicht überschrieben werden kann
  • Machen Sie alle Mitgliedsvariablen privat und endgültig
  • Geben Sie ihre Setter-Methoden nicht an
  • Objektreferenz sollte während der Bauphase nicht durchgesickert sein

1

Die folgenden Schritte müssen berücksichtigt werden, wenn Sie eine Klasse als unveränderliche Klasse möchten.

  1. Klasse sollte als endgültig markiert werden
  2. Alle Felder müssen privat und endgültig sein
  3. Ersetzen Sie Setter durch Konstruktoren (um einer Variablen einen Wert zuzuweisen).

Werfen wir einen Blick auf das, was wir oben eingegeben haben:

//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());

    }
}

0

Häufig ignorierte, aber wichtige Eigenschaften für unveränderliche Objekte

Hinzufügen von mehr als auf die Antwort , die von @ nsfyn55 die folgenden Aspekte müssen auch für Objekt Unveränderlichkeit in Betracht gezogen werden, die von sind prime Bedeutung

Betrachten Sie die folgenden Klassen:

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());

  }

 }

Es folgt die Ausgabe von MutabilityCheck:

 Foo
 Bar

Es ist wichtig sich das zu merken,

  1. Konstruieren veränderlicher Objekte auf einem unveränderlichen Objekt (über den Konstruktor), entweder durch 'Kopieren' oder 'Cloing' in Instanzvariablen der unveränderlichen Objekte, die durch die folgenden Änderungen beschrieben werden:

    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;
      } 
     }

gewährleistet immer noch keine vollständige Unveränderlichkeit, da Folgendes aus der Klasse MutabilityCheck weiterhin gültig ist:

  iMC.getMutClass().setName("Blaa");
  1. Das Ausführen von MutabilityCheck mit den in 1. vorgenommenen Änderungen führt jedoch zu folgender Ausgabe:

    Foo
    Foo
  2. Um eine vollständige Unveränderlichkeit für ein Objekt zu erreichen, müssen auch alle seine abhängigen Objekte unveränderlich sein


0

Ab JDK 14+ mit JEP 359 können wir " records" verwenden. Es ist die einfachste und stressfreieste Art, unveränderliche Klassen zu erstellen.

Eine Datensatzklasse ist ein flach unveränderlicher , transparenter Träger für einen festen Satz von Feldern, der als Datensatz bezeichnet componentswird und eine stateBeschreibung für den Datensatz enthält. Jedes componentführt zu einem finalFeld, das den angegebenen Wert enthält, und einer accessorMethode zum Abrufen des Werts. Der Feldname und der Zugriffsname stimmen mit dem Namen der Komponente überein.

Betrachten wir das Beispiel zum Erstellen eines unveränderlichen Rechtecks

record Rectangle(double length, double width) {}

Keine Notwendigkeit, einen Konstruktor zu deklarieren, keine Notwendigkeit, equals& hashCodeMethoden zu implementieren . Nur alle Datensätze benötigen einen Namen und eine Statusbeschreibung.

var rectangle = new Rectangle(7.1, 8.9);
System.out.print(rectangle.length()); // prints 7.1

Wenn Sie den Wert während der Objekterstellung überprüfen möchten, müssen wir den Konstruktor explizit deklarieren.

public Rectangle {

    if (length <= 0.0) {
      throw new IllegalArgumentException();
    }
  }

Der Datensatzkörper kann statische Methoden, statische Felder, statische Initialisierer, Konstruktoren, Instanzmethoden und verschachtelte Typen deklarieren.

Instanzmethoden

record Rectangle(double length, double width) {

  public double area() {
    return this.length * this.width;
  }
}

statische Felder, Methoden

Da state Teil der Komponenten sein sollte, können wir Datensätzen keine Instanzfelder hinzufügen. Wir können jedoch statische Felder und Methoden hinzufügen:

record Rectangle(double length, double width) {

  static double aStaticField;

  static void aStaticMethod() {
    System.out.println("Hello Static");
  }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.