Immutable Classes
Immutable classes are those whose object once created will not change its value. All wrapper classes in Java are Immutable classes. For eg. String, BigInteger, Byte, etc.
Immutable classes are good for caching because you don’t have to worry about the value changes.
Another benefit of the immutable class is that it is inherently thread-safe.
How to Create an immutable class in Java?
To create an immutable class in Java, we need to make sure that the class we create by any mechanism should above to provide a way to change its object's values. To do that we can follow few rules, which help us to prevent that behavior.
- Declare the class as final so it cannot be extended. If the class cannot be extended the child cannot make any changes.
- All class members should be private so they cannot be accessed outside of class.
- The class should not contain any setter methods to change the value of class members.
- The getter method should return the copy of class members.
- Variables are initialized only by using the constructor.
- Perform cloning or deep copy of objects in the getter methods to return a copy rather than returning the actual object reference.
Example 1:
import java.util.HashMap;
import java.util.Map;
// class is declared final
final class Immutable {
// private class members
private final String name;
private final int date;
private final Map<String, String> metadata;
public Immutable(String name, int date, Map<String, String> metadata) {
// class members are initialized using constructor
this.name = name;
this.date = date;
Map<String, String> tempMap = new HashMap<>();
for (Map.Entry<String, String> entry : metadata.entrySet()) {
tempMap.put(entry.getKey(), entry.getValue());
}
this.metadata = tempMap;
}
// getter method returns the copy of class members
public String getName() {
return name;
}
public int getDate() {
return date;
}
public Map<String, String> getMetadata() {
// Creating Map with HashMap reference
Map<String, String> tempMap = new HashMap<>();
for (Map.Entry<String, String> entry :
this.metadata.entrySet()) {
tempMap.put(entry.getKey(), entry.getValue());
}
return tempMap;
}
}
Example 2:
final class Immutable {
private final Mutable mutableClass;
public Immutable(Mutable mutableClass) {
super();
this.mutableClass = mutableClass;
}
public Mutable getMutableClass() throws CloneNotSupportedException {
return (Mutable) mutableClass.clone();
}
}
class Mutable implements Cloneable {
public String variable;
public Mutable(String variable) {
super();
this.variable = variable;
}
public String getVariable() {
return variable;
}
public void setVariable(String variable) {
this.variable = variable;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Mutable{" +
"variable='" + variable + '\'' +
'}';
}
}
public class MainClass {
public static void main(String[] args) throws Exception {
Immutable immutable = new Immutable(new Mutable("Some String"));
Mutable mutable = immutable.getMutableClass();
System.out.println(mutable);
mutable.setVariable("Updated String");
System.out.println(immutable.getMutableClass());
}
}
#HappyCoding
Top comments (0)