How to create an immutable class in java

How to create an immutable class in java. if the student’s class is related (address), how to create an immutable class. I want to make the class below immutable

final public class Student { private final Address add; private final int sid; public Student(int sid, String name, Address add) { super(); this.sid = sid; this.name = name; this.add = add; } private final String name; public int getSid() { return sid; } public final String getName() { return name; } @Override public String toString() { return "Student [add=" + add + ", name=" + name + ", sid=" + sid + "]"; } public Address getAdd() { return add; } } //I want to make the class below immutable public class Address { public int getAid() { return aid; } public String getStreet() { return street; } @Override public String toString() { return "Address [aid=" + aid + ", street=" + street + "]"; } int aid; String street; public Address(int aid, String street) { super(); this.aid = aid; this.street = street; } } public class First { public static void main(String[] args) { Address myAdd=new Address(179,"Maihill"); Student st=new Student(99,"anoj",myAdd); System.out.println(st.toString()); myAdd.aid=2376; System.out.println(st); System.out.println("***************"); Address pAdd=st.getAdd(); //Here modified address instance then how we can make immutable. pAdd.aid=788; System.out.println(st); } } 

Here we can modify address instances. Please give me an idea

+8
java
source share
6 answers

The key points for immutable are:

  • no configuration methods
  • make variables private and final
  • return lists using Collections.unmodifiableList - never return any mutable field; always return either a copy (if necessary, a deep one) or an immutable version of the field
  • make the class final
  • If variables are changed inside the class, this change is not displayed and has no effect outside the class (including the effect on things like equals() and hashcode() ).
+16
source share

In your Address class, you must make your fields private (should) and final (must), like this -

 public final class Address { // so no sub-classes can be made. private final int aid; // private and final. private final String street; // private and final. // as before. } 

You also cannot have setter methods, but when the fields are final, which is not a big problem (since any setter method will give a compiler error).

+4
source share

It’s good that you made the student semantically unchanged:

  • His attributes are final
  • they have immutable types (except address)
  • and they are initialized in the constructor.

You must apply the same thing to the Address class so that it becomes unchanged, and then the entire Student state will be unchanged. So it will be:

 public final class Address { private final int aid; private final String street; public Address(int aid, String street) { this.aid = aid; this.street = street; } public int getAid() { return aid; } public String getStreet() { return street; } .... } 

Fortunately, you do not have any modifiable types (some of the most famous are Date , Collection and Maps ), otherwise you will also consider them.

If you have any mutable attributes, you must copy it to the constructor, and you must return an immutable copy or a copy of it where the state leak occurs.

For example, if your Student class had the birthDate attribute, you should do something like:

 public final class Student { private final Date birthDate; public Student(int sid, String name, Address address, Date birthDate) { this.sid = sid; this.name = name; this.address = address; this.birthDate = (birthDate == null) ? null : new Date(birthDate.getTime()); } public Date getBirthDate() { return (birthDate == null) ? null : new Date(birthDate.getTime()); } .... } 
+3
source share

This is enough. The declared final cannot be mutated, and since arguments are needed in the constructor, getters are redundant.

 final public class Student { public final Address add; public final int sid; public final String name; public Student(int sid, String name, Address add) { super(); this.sid = sid; this.name = name; this.add = add; } @Override public String toString() { return "Student [add=" + add + ", name=" + name + ", sid=" + sid + "]"; } } 

address and studentId/id would be better names for fields.

+1
source share

To make a class immutable, follow these five rules:

from Effective Java - Third Edition - Chapter 4

  1. Do not provide methods that change the state of objects (known as mutators) .
  2. Make sure the class cannot be extended. This allows reckless or malicious subclasses to violate the unchanging behavior of the class, behaving as if the state of the objects has changed. Preventing subclassing is usually done by creating a final class or providing a private constructor
  3. Make all fields final. This clearly expresses your intentions in accordance with the requirements of the system. In addition, it is necessary to ensure the correct behavior if the link to the newly created instance is transferred from one thread to another without synchronization, as indicated in the memory model
  4. Make all fields private. This prevents clients from gaining access to mutable objects referenced by the fields and directly modifying those objects. Although it is technically permissible for immutable classes to have open final fields containing primitive values ​​or references to immutable objects, this is not recommended as this eliminates a change in internal representation in a later release.
  5. Provide exclusive access to any mutable components. If your class has fields referencing mutable objects, make sure that clients of this class cannot get references to these objects. Never initialize such a field for an object reference provided by a client or return a field from an accessor. Make protective copies (element 50) in the constructors, access methods, and readObject methods.

Complex.java - an example of an immutable class

 public final class Complex { private final double re; private final double im; public Complex(double re, double im) { this.re = re; this.im = im; } public double realPart() { return re; } public double imaginaryPart() { return im; } public Complex plus(Complex c) { return new Complex(re + c.re, im + c.im); } public Complex minus(Complex c) { return new Complex(re - c.re, im - c.im); } public Complex times(Complex c) { return new Complex(re * c.re - im * c.im, re * c.im + im * c.re); } public Complex dividedBy(Complex c) { double tmp = c.re * c.re + c.im * c.im; return new Complex((re * c.re + im * c.im) / tmp, (im * c.re - re * c.im) / tmp); } @Override public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Complex)) return false; Complex c = (Complex) o; // See page 47 to find out why we use compare instead of == return Double.compare(c.re, re) == 0 && Double.compare(c.im, im) == 0; } @Override public int hashCode() { return 31 * Double.hashCode(re) + Double.hashCode(im); } @Override public String toString() { return "(" + re + " + " + im + "i)"; } } 
0
source share

First we need to discuss what is immutable in Java.
In Java, immutable means that your state does not change after it is initialized. the best example of an immutable class is String.

We can also create our own immutable class, you must take the following steps.

  • Declare Class as final:

     Why? : As per the java final class can not be extended. 
  • Declare all fields as private.

     Why? : Because private member have not direct access out side of the class 
  • Do not provide an installation method for this private field

     Why? : If you provide the setter method for the private members so you can access it out side of the class. 
  • Make all fields final.

     Why?: As per the java final variable can be assigned only once. 
  • Initialize all fields through the constructor using deep copy.

      import java.util.HashMap; import java.util.Iterator; public final class ImmutableClassExample { private final int id; private final String name; private final HashMap<String,String> testMap; public int getId() { return id; } public String getName() { return name; } /** * Accessor function for mutable objects */ public HashMap<String, String> getTestMap() { //return testMap; return (HashMap<String, String>) testMap.clone(); } /** * Constructor performing Deep Copy * @param i * @param n * @param hm */ public ImmutableClassExample(int i, String n, HashMap<String,String> hm){ System.out.println("Performing Deep Copy for Object initialization"); this.id=i; this.name=n; HashMap<String,String> tempMap=new HashMap<String,String>(); String key; Iterator<String> it = hm.keySet().iterator(); while(it.hasNext()){ key=it.next(); tempMap.put(key, hm.get(key)); } this.testMap=tempMap; } /** * Constructor performing Shallow Copy * @param i * @param n * @param hm */ /** public ImmutableClassExample(int i, String n, HashMap<String,String> hm){ System.out.println("Performing Shallow Copy for Object initialization"); this.id=i; this.name=n; this.testMap=hm; } */ /** * To test the consequences of Shallow Copy and how to avoid it with Deep Copy for creating immutable classes * @param args */ public static void main(String[] args) { HashMap<String, String> h1 = new HashMap<String,String>(); h1.put("1", "first"); h1.put("2", "second"); String s = "original"; int i=10; ImmutableClassExample ce = new ImmutableClassExample(i,s,h1); //Lets see whether its copy by field or reference System.out.println(s==ce.getName()); System.out.println(h1 == ce.getTestMap()); //print the ce values System.out.println("ce id:"+ce.getId()); System.out.println("ce name:"+ce.getName()); System.out.println("ce testMap:"+ce.getTestMap()); //change the local variable values i=20; s="modified"; h1.put("3", "third"); //print the values again System.out.println("ce id after local variable change:"+ce.getId()); System.out.println("ce name after local variable change:"+ce.getName()); System.out.println("ce testMap after local variable change:"+ce.getTestMap()); HashMap<String, String> hmTest = ce.getTestMap(); hmTest.put("4", "new"); System.out.println("ce testMap after changing variable from accessor methods:"+ce.getTestMap()); } } 
0
source share

All Articles