Tutorial

How To Create an Immutable Class in Java

Updated on November 17, 2022
authorauthor

Pankaj and Andrea Anderson

How To Create an Immutable Class in Java

Introduction

This article provides an overview of how to create an immutable class in Java programming.

An object is immutable when its state doesn’t change after it has been initialized. For example, String is an immutable class and, once instantiated, the value of a String object never changes. Learn more about why the String class is immutable in Java.

Because an immutable object can’t be updated, programs need to create a new object for every change of state. However, immutable objects also have the following benefits:

  • An immutable class is good for caching purposes because you don’t have to worry about the value changes.
  • An immutable class is inherently thread-safe, so you don’t have to worry about thread safety in multi-threaded environments.

Learn more about multi-threading in Java and browse the Java Multi-Threading Interview Questions.

Creating an Immutable Class in Java

To create an immutable class in Java, you need to follow these general principles:

  1. Declare the class as final so it can’t be extended.
  2. Make all of the fields private so that direct access is not allowed.
  3. Don’t provide setter methods for variables.
  4. Make all mutable fields final so that a field’s value can be assigned only once.
  5. Initialize all fields using a constructor method performing deep copy.
  6. Perform cloning of objects in the getter methods to return a copy rather than returning the actual object reference.

The following class is an example that illustrates the basics of immutability. The FinalClassExample class defines the fields and provides the constructor method that uses deep copy to initialize the object. The code in the main method of the FinalClassExample.java file tests the immutability of the object.

Create a new file called FinalClassExample.java and copy in the following code:

FinalClassExample.java
import java.util.HashMap;
import java.util.Iterator;

public final class FinalClassExample {

	// fields of the FinalClassExample class
	private final int id;
	
	private final String name;
	
	private final HashMap<String,String> testMap;

	
	public int getId() {
		return id;
	}

	public String getName() {
		return name;
	}

	// Getter function for mutable objects

	public HashMap<String, String> getTestMap() {
		return (HashMap<String, String>) testMap.clone();
	}

	// Constructor method performing deep copy
	
	public FinalClassExample(int i, String n, HashMap<String,String> hm){
		System.out.println("Performing Deep Copy for Object initialization");

		// "this" keyword refers to the current object
		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;
	}

	// Test the immutable class

	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;
		
		FinalClassExample ce = new FinalClassExample(i,s,h1);
		
		// 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 getter methods: "+ce.getTestMap());

	}

}

Compile and run the program:

  1. javac FinalClassExample.java
  2. java FinalClassExample

Note: You might get the following message when you compile the file: Note: FinalClassExample.java uses unchecked or unsafe operations because the getter method is using an unchecked cast from HashMap<String,String> to Object. You can ignore the compiler warning for the purposes of this example.

You get the following output:

Output
Performing Deep Copy for Object initialization ce id: 10 ce name: original ce testMap: {1=first, 2=second} ce id after local variable change: 10 ce name after local variable change: original ce testMap after local variable change: {1=first, 2=second} ce testMap after changing variable from getter methods: {1=first, 2=second}

The output shows that the HashMap values didn’t change because the constructor uses deep copy and the getter function returns a clone of the original object.

What happens when you don’t use deep copy and cloning

You can make changes to the FinalClassExample.java file to show what happens when you use shallow copy instead of deep copy and return the object insetad of a copy. The object is no longer immutable and can be changed. Make the following changes to the example file (or copy and paste from the code example):

  • Delete the constructor method providing deep copy and add the constructor method providing shallow copy that is highlighted in the following example.
  • In the getter function, delete return (HashMap<String, String>) testMap.clone(); and add return testMap;.

The example file should now look like this:

FinalClassExample.java
import java.util.HashMap;
import java.util.Iterator;

public final class FinalClassExample {

	// fields of the FinalClassExample class
	private final int id;
	
	private final String name;
	
	private final HashMap<String,String> testMap;

	
	public int getId() {
		return id;
	}

	public String getName() {
		return name;
	}

	// Getter function for mutable objects

	public HashMap<String, String> getTestMap() {
		return testMap;
	}

	//Constructor method performing shallow copy

	public FinalClassExample(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;
	}

	// Test the immutable class

	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;
		
		FinalClassExample ce = new FinalClassExample(i,s,h1);
		
		// 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 getter methods: "+ce.getTestMap());

	}

}

Compile and run the program:

  1. javac FinalClassExample.java
  2. java FinalClassExample

You get the following output:

Output
Performing Shallow Copy for Object initialization ce id: 10 ce name: original ce testMap: {1=first, 2=second} ce id after local variable change: 10 ce name after local variable change: original ce testMap after local variable change: {1=first, 2=second, 3=third} ce testMap after changing variable from getter methods: {1=first, 2=second, 3=third, 4=new}

The output shows that the HashMap values got changed because the constructor method uses shallow copy there is a direct reference to the original object in the getter function.

Conclusion

You’ve learned some of the general principles to follow when you create immutable classes in Java, including the importance of deep copy. Continue your learning with more Java tutorials.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the author(s)

Category:
Tutorial
Tags:

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
JournalDev
DigitalOcean Employee
DigitalOcean Employee badge
December 23, 2010

… and here is a translation of the entire exercise into Scala, except without the wasteful copying and cloning, and with correct equals and hashCode methods: case class FinalClassExample(id: Int, name: String, testMap: Map[String,String])

- Ken

JournalDev
DigitalOcean Employee
DigitalOcean Employee badge
December 23, 2010

I didn’t understood what are you trying to point here?

- Pankaj

JournalDev
DigitalOcean Employee
DigitalOcean Employee badge
December 23, 2010

I belive that he was trying to point out that Scala lets you create immutable classes in more concise way. I’m new to Scala myself and already I love and often use these one liners. Less code less opportunities to make mistakes :)

- Paweł Chłopek

JournalDev
DigitalOcean Employee
DigitalOcean Employee badge
December 23, 2010

Thats a completely new thing to me… Got something new to learn now… will dig into this soon :)

- Pankaj

    JournalDev
    DigitalOcean Employee
    DigitalOcean Employee badge
    December 23, 2010

    Shouldn’t it be “shallow copy” instead of “swallow copy” unless I am missing something?

    - Shantanu Kumar

    JournalDev
    DigitalOcean Employee
    DigitalOcean Employee badge
    December 23, 2010

    Thanks for pointing out the typo error. Corrected now to shallow copy.

    - Pankaj

      JournalDev
      DigitalOcean Employee
      DigitalOcean Employee badge
      December 23, 2010

      why don’t you just do this: import static java.util.Collections.unmodifiableMap; public final class FinalClassExample { ... private final Map testMap; public FinalClassExample(int i, String n, Map m){ id = i; name = n; testMap = unmodifiableMap(new HashMap (m)); } public Map getTestMap() { return testMap; } ... }

      - John

      JournalDev
      DigitalOcean Employee
      DigitalOcean Employee badge
      December 23, 2010

      In this case, when we will get the testMap from getTestMap() function, we will not be allowed to modify it and it will throw exception. Also in that case again we are passing the reference and the values will change accordingly. Try executing this class: package com.journeldev.java; import static java.util.Collections.unmodifiableMap; import java.util.HashMap; import java.util.Map; public final class FinalClassExample1 { private final Map testMap; public Map getTestMap() { return testMap; } public FinalClassExample1(Map hm) { this.testMap = unmodifiableMap(hm); } public static void main(String[] args) { HashMap h1 = new HashMap(); h1.put("1", "first"); h1.put("2", "second"); FinalClassExample1 ce = new FinalClassExample1(h1); System.out.println("ce testMap:" + ce.getTestMap()); h1.put("3", "third"); System.out.println("ce testMap after local variable change:"+ ce.getTestMap()); Map hmTest = ce.getTestMap(); hmTest.put("4", "new"); System.out.println("ce testMap after changing variable from accessor methods:"+ ce.getTestMap()); } } Output will be: ce testMap:{2=second, 1=first} ce testMap after local variable change:{3=third, 2=second, 1=first} Exception in thread “main” java.lang.UnsupportedOperationException at java.util.Collections$UnmodifiableMap.put(Collections.java:1285) at com.journeldev.java.FinalClassExample1.main(FinalClassExample1.java:33)

      - Pankaj

      JournalDev
      DigitalOcean Employee
      DigitalOcean Employee badge
      December 23, 2010

      Pankaj, You should not be allowed to modify a map you get from getTestMap. Objects coming from an immutable object, I would expect to also be immutable so you can not change the internals of the object after it is created. A mutable map may imply that the objects map is changed. Sure you can document that the object returned is new, but being defensive upfront seems better. Another alternative is to never return collections. Instead, define a forEach method that takes a function: public void forEach(Function fn) { for(Thing t : Iterable collection) { fn.apply(t); } }

      - Steve

      JournalDev
      DigitalOcean Employee
      DigitalOcean Employee badge
      December 24, 2010

      I am not sure why the map returned from getTestMap method should not be allowed to modify. Suppose the list contains some 1000 items and client wants to add 5 more to make their own immutable object instance, in this case its better to let them modify the returned object and do whatever they want on it. Usually, we have setter methods to change the state of object, so just by changing the returned object you should not think that the object state has been changed because the internal implementation is not known to us(as a client).

      - Pankaj

        JournalDev
        DigitalOcean Employee
        DigitalOcean Employee badge
        December 24, 2010

        you didn’t notice that I wrote: this.testMap = modifiableMap(**new HashMap** (m)) `` so you couldn't change the inner map after construction. and I agree with Steve that the map returned by getTestMap() should not be modifiable as this would give the false impression that you're actually changing the immutable object. in that case I would prefer doing something like this: `FinalClassExample example = new FinalClassExample(...); Map newMap = new HashMap(example.getTestMap()); newMap.put("hello", "world");` ``

        - John

        JournalDev
        DigitalOcean Employee
        DigitalOcean Employee badge
        December 24, 2010

        Ok agreed that this will work but then its not generic. What if its some generic mutable class like Date or may be user defined class where you don’t have this feature. This example is intended to provide a generic way to create immutable classes. As for changing the object state, that is why we have setter methods and I still prefer it doing like that… but again it depends on your application requirements and design.

        - Pankaj

          JournalDev
          DigitalOcean Employee
          DigitalOcean Employee badge
          December 23, 2010

          In Groovy you can annotate the class as @Immutable and get /almost/ similar results to the scala example without all the boilerplate. IMHO Scala is better for it’s immutable support though. Also, don’t forget that Java Date, Dimension, and other JDK classes are not immutable as well, so you need to make defensive copies of those classes as well.

          - Hamlet D’Arcy

          JournalDev
          DigitalOcean Employee
          DigitalOcean Employee badge
          December 23, 2010

          Exactly, for all the mutable objects we need to return the defensive copy rather than same object reference. Have to dig into Scala now.

          - Pankaj

            JournalDev
            DigitalOcean Employee
            DigitalOcean Employee badge
            December 23, 2010

            Out of curiosity, why the requirement to have the class be marked as final so as not to be extended? What does disallowing subclasses actually provide in terms of allowing objects of this type to be immutable? Further, you don’t have to mark fields as private only just so long as you can guarantee that all constructor’s of the class properly initialize all of the fields. As a side note, you *can* have setters, but with the nuance that instead of changing an internal field, what the setter really does is specify a return type of the class the method is on, and then behind the scenes creates a new object using a constructor that accepts all internal fields, using the internally held state in for all params with the exception of the field represented by the setter called since you want the new object to have that field updated.

            - whaley

            JournalDev
            DigitalOcean Employee
            DigitalOcean Employee badge
            December 23, 2010

            If the class is not marked as final then its function can be overridden in the subclass either accidentally or intentionally. So its more related to keep the object secure. For this either all the getter methods can be made final or the class itself - this is again a design decision and depends on the requirement. Again if the fields wont be private then client application can override the value. Make the HashMap as public in the code and run the below code to see yourself. FinalClassExample fce = new FinalClassExample(1,"", new HashMap()); System.out.println(fce.testMap); HashMap hm = fce.testMap; hm.put("1", "1"); System.out.println(fce.testMap); Having a setter function will give the feeling that the actual object has been modified whereas internally creating a new object. Its better to client application know that its immutable (like String).

            - Pankaj

              JournalDev
              DigitalOcean Employee
              DigitalOcean Employee badge
              May 5, 2011

              It’s super webpage, I was looking for something like this

              - Łomża Zuhlke

                JournalDev
                DigitalOcean Employee
                DigitalOcean Employee badge
                June 2, 2012

                Thanks mate, great details… – Anish Sneh

                - Anish Sneh

                JournalDev
                DigitalOcean Employee
                DigitalOcean Employee badge
                October 17, 2012

                Thanks for the kind words.

                - Pankaj

                  JournalDev
                  DigitalOcean Employee
                  DigitalOcean Employee badge
                  September 19, 2013

                  Thanks, you know it and you know how to explain it too! I will definitely read more of your articles :)

                  - Mirey

                    JournalDev
                    DigitalOcean Employee
                    DigitalOcean Employee badge
                    August 18, 2014

                    Thanks for the detailed tutorial, well written and the flow goes exactely to showing up almost the need of every instruction in the code :) One side question, even if I know we are talking about Objects immutability,but what about the other instance variables you introucted in the FinalClassExample (id, name)? Is there any way to make them immutable?

                    - Marwen

                    JournalDev
                    DigitalOcean Employee
                    DigitalOcean Employee badge
                    August 18, 2014

                    int and String both are already immutable, since there are no setter methods for them. For any other class variables, you should return a deep copy of the variable to avoid mutability.

                    - Pankaj

                      JournalDev
                      DigitalOcean Employee
                      DigitalOcean Employee badge
                      November 10, 2014

                      Should not be String name declared as a not final? Its not mutable anyway.

                      - Ramakant

                        JournalDev
                        DigitalOcean Employee
                        DigitalOcean Employee badge
                        November 22, 2014

                        Hi Pankaj, It was a great learning about creating Immutable objects.If you are performing step 5 and 6 then step 4 is not required I guess. You are not storing or returning original reference of HashMap, You are using clone concept for that, Hence as a result client application have no way to reassign new object to declared HaspMap. Please correct me If I am missing some thing Thanks& Regards Rais Alam

                        - Rais Alam

                          JournalDev
                          DigitalOcean Employee
                          DigitalOcean Employee badge
                          February 2, 2015

                          Can you please describe no 6. more deeply.I am not able to understand it.

                          - mahi

                            JournalDev
                            DigitalOcean Employee
                            DigitalOcean Employee badge
                            February 12, 2015

                            Excellent post!!

                            - S

                              JournalDev
                              DigitalOcean Employee
                              DigitalOcean Employee badge
                              March 7, 2015

                              thanx i disable ABP for u

                              - ahmed

                              JournalDev
                              DigitalOcean Employee
                              DigitalOcean Employee badge
                              March 7, 2015

                              Thanks Ahmed, I appreciate it.

                              - Pankaj

                                JournalDev
                                DigitalOcean Employee
                                DigitalOcean Employee badge
                                March 14, 2015

                                I can modify the object using ce.testMap.put(“10”, “ten”); Output: Performing Deep Copy for Object initialization true false ce id:10 ce name:original ce testMap:{2=second, 1=first} ce id after local variable change:10 ce name after local variable change:original ce testMap after local variable change:{2=second, 1=first, 10=ten} ce testMap after changing variable from accessor methods:{2=second, 1=first, 10=ten}

                                - Bijoy

                                JournalDev
                                DigitalOcean Employee
                                DigitalOcean Employee badge
                                October 16, 2016

                                how to overcome this case; ce.testMap.put(“10”, “ten”); //ce testMap after local variable change:{2=second, 1=first, 10=ten} //ce testMap after changing variable from accessor methods:{2=second, 1=first, 10=ten}

                                - parasuram tanguturu

                                JournalDev
                                DigitalOcean Employee
                                DigitalOcean Employee badge
                                April 27, 2017

                                testMap is private variable and out side class it wont be available. Its just a Example code that is why in main you are able to do ce.testMap but in real application you wont be as generally you dont do such operations in POJO class.

                                - JavaRocker

                                  JournalDev
                                  DigitalOcean Employee
                                  DigitalOcean Employee badge
                                  September 14, 2015

                                  private final String name; …Why this is final …String is already final …do we need to declare it again…???

                                  - Ajaz

                                  JournalDev
                                  DigitalOcean Employee
                                  DigitalOcean Employee badge
                                  February 6, 2017

                                  “String is already final.” - yes , it is , but that final is at class level which means you can’t extend the String class, while that "private final String " is for variable , so that we cant change the value of that object once initialized.

                                  - Vinay

                                    JournalDev
                                    DigitalOcean Employee
                                    DigitalOcean Employee badge
                                    December 18, 2015

                                    Thank you Pankaj. I’m a big fan of your writing skills. You cover every details and explain concepts in easy to understand language. Thanks again.

                                    - Vijay Nandwana

                                      JournalDev
                                      DigitalOcean Employee
                                      DigitalOcean Employee badge
                                      December 22, 2015

                                      Very easy to understand and useful post!!

                                      - Vineet kaushik

                                        JournalDev
                                        DigitalOcean Employee
                                        DigitalOcean Employee badge
                                        December 28, 2015

                                        Thanks for great article! Can we use testMap.clone() in the constructor instead of going through all of the map items with Iterator?

                                        - Bektur Toktosunov

                                          JournalDev
                                          DigitalOcean Employee
                                          DigitalOcean Employee badge
                                          January 13, 2017

                                          Hi Pankaj I didn’t Understood the System.out.println(h1 == ce.getTestMap()) answer is False. Can you Please explain why it is false.

                                          - WAA

                                          JournalDev
                                          DigitalOcean Employee
                                          DigitalOcean Employee badge
                                          April 20, 2017

                                          On this statement we are just checking the reference of h1 is pointing to the one that of our final class TestMap reference, which in this case is no, because we have made a new copy of h1 hashmap and copied it in TempHashMap which is an completely new Object, & then the reference of this temp map is assign to TestHashMap. Hence this reference are pointing to, two different Object all together.

                                          - Ankush K

                                            JournalDev
                                            DigitalOcean Employee
                                            DigitalOcean Employee badge
                                            March 1, 2017

                                            hi pankaj, i love to read your blog. here i found a hack at main() using a reflection how to prevent it. Class mc = ce.getClass(); Field fs = mc.getDeclaredField(“name”); fs.setAccessible(true); fs.set(ce, “hacked”); System.out.println(“ce name after reflection hack:”+ce.getName());

                                            - tabish

                                            JournalDev
                                            DigitalOcean Employee
                                            DigitalOcean Employee badge
                                            March 22, 2017

                                            You cannot do this since name is final

                                            - shashank

                                            JournalDev
                                            DigitalOcean Employee
                                            DigitalOcean Employee badge
                                            August 13, 2018

                                            It does work.

                                            - Umang Gupta

                                              JournalDev
                                              DigitalOcean Employee
                                              DigitalOcean Employee badge
                                              April 1, 2017

                                              When you make the field final, Why making the variable private is mandate?

                                              - Rahul

                                                JournalDev
                                                DigitalOcean Employee
                                                DigitalOcean Employee badge
                                                April 6, 2017

                                                I it necessary to have variable as final?? We can achive it without it also, there is no statement to change varable.

                                                - Pratyush

                                                  JournalDev
                                                  DigitalOcean Employee
                                                  DigitalOcean Employee badge
                                                  April 13, 2017

                                                  Hi setter method for map provides shallow copy only though clone method so that we can change the value later. How come you can say its immutable ?

                                                  - Anbu

                                                  JournalDev
                                                  DigitalOcean Employee
                                                  DigitalOcean Employee badge
                                                  November 30, 2017

                                                  I believe, you are talking about getter method. public HashMap getTestMap() { //return testMap; return (HashMap) testMap.clone(); } I believe, It should return a copy by deep cloning.

                                                  - Prakash

                                                  JournalDev
                                                  DigitalOcean Employee
                                                  DigitalOcean Employee badge
                                                  November 30, 2017

                                                  I believe, In this example, Shallow copy would also work fine as long as we are storing immutable String object in HashMap. In case, if we need to store mutable object in HashMap. We should do deep cloning

                                                  - Prakash

                                                    JournalDev
                                                    DigitalOcean Employee
                                                    DigitalOcean Employee badge
                                                    May 14, 2017

                                                    Which Java version ? or forgot the Final variables initialisation?

                                                    - Tanmai

                                                    JournalDev
                                                    DigitalOcean Employee
                                                    DigitalOcean Employee badge
                                                    May 22, 2017

                                                    Final variables can be left uninitialized in declaration if initialization is provided by constructor.

                                                    - Manoj Kumar Vohra

                                                      JournalDev
                                                      DigitalOcean Employee
                                                      DigitalOcean Employee badge
                                                      June 25, 2017

                                                      Correct output is:: Performing Shallow Copy for Object initialization true false ce id:10 ce name:original ce testMap:{2=second, 1=first} ce id after local variable change:10 ce name after local variable change:original ce testMap after local variable change:{3=third, 2=second, 1=first} ce testMap after changing variable from accessor methods:{3=third, 2=second, 1=f irst}

                                                      - Rushabh

                                                        JournalDev
                                                        DigitalOcean Employee
                                                        DigitalOcean Employee badge
                                                        July 6, 2017

                                                        I am not clear on Point 5 initialization swallow or Deep are comparison not initialization. swallow comparison is done by == and Deep comparison by equal / equalignorecase Did you mean initialization should be done at constructor with safer way without exposing identity of the fields?

                                                        - kuldeep patil

                                                          JournalDev
                                                          DigitalOcean Employee
                                                          DigitalOcean Employee badge
                                                          September 13, 2017

                                                          I also wrote an article with a complete different view and you may have a look, https://www.codedjava.com/2017/09/immutable-objects-in-java\_50.html Thanks,

                                                          - Sameera

                                                            JournalDev
                                                            DigitalOcean Employee
                                                            DigitalOcean Employee badge
                                                            September 23, 2017

                                                            What if we remove the final access modifier from class as we are independently handling all the fields or methods of this class. And if some one extend this class then they doesn’t impact this class instance. Please suggest.

                                                            - Vaibhav Jetly

                                                            JournalDev
                                                            DigitalOcean Employee
                                                            DigitalOcean Employee badge
                                                            November 23, 2018

                                                            But then it is circumventing the intent of the class. If you want additional behavior from a different class, create a different class and have the immutable one as an instance member of that class.

                                                            - Mike New

                                                              JournalDev
                                                              DigitalOcean Employee
                                                              DigitalOcean Employee badge
                                                              January 29, 2018

                                                              Your getter method for HashMap can be in that way public HashMap getTestMap() { //return testMap; //HashMap tempMap=new HashMap(); return new HashMap(testMap); }

                                                              - TEJENDRA PRATAP SINGH

                                                                JournalDev
                                                                DigitalOcean Employee
                                                                DigitalOcean Employee badge
                                                                April 27, 2018

                                                                correct output is: Performing Shallow Copy for Object initialization true false ce id:10 ce name:original ce testMap:{1=first, 2=second} ce id after local variable change:10 ce name after local variable change:original ce testMap after local variable change:{1=first, 2=second, 3=third} ce testMap after changing variable from accessor methods:{1=first, 2=second, 3=third}

                                                                - Hagos haile

                                                                JournalDev
                                                                DigitalOcean Employee
                                                                DigitalOcean Employee badge
                                                                May 31, 2019

                                                                Yeah Thats what i was thinking .ce testMap after changing variable from accessor methods:{1=first, 2=second, 3=third} 4=new wont be get added

                                                                - Vigilante

                                                                  JournalDev
                                                                  DigitalOcean Employee
                                                                  DigitalOcean Employee badge
                                                                  May 19, 2018

                                                                  Hi Pankaj, What will happen if we do not declare class as final, since member variables are privare so can not be extendable. I am here trying to understand why we need final for class and its member variable. Is there any way state of a class can be modified if we don’t declare class and its variables final? Thanks, Prahlad.

                                                                  - Prahlad Kumar

                                                                  JournalDev
                                                                  DigitalOcean Employee
                                                                  DigitalOcean Employee badge
                                                                  August 16, 2018

                                                                  You need the class as final so, that it cannot be extended further and it’s implememtation should not be changed by overriding the methods and by creating new variables. Making variables as final will make sure two things, 1. Compiler will flag error if any reassignment will take place 2. It will give readability to the code to other people who are working on the same class that these variables are not supposed to be changed. Basically it is because of IMHO

                                                                  - Gunjal Shrivastava

                                                                  JournalDev
                                                                  DigitalOcean Employee
                                                                  DigitalOcean Employee badge
                                                                  April 25, 2021

                                                                  But if the variables are private and we do not provide any setter methods, how will their values ever change once initialized? Reassignment is not possible in this case. Making the class final is also not necessary. What method can a subclass override that will change the private member variables of the parent class? Is there something I am missing?

                                                                  - Vaibhav Souveer

                                                                    JournalDev
                                                                    DigitalOcean Employee
                                                                    DigitalOcean Employee badge
                                                                    June 24, 2018

                                                                    Hi Pankaj, Thanks for writing such an informative article. I would like to know what if my all member variables are immutable like all Strings or Wrappers?, Do I still need to follow above steps? Thanks,

                                                                    - Jitendra Singh

                                                                    JournalDev
                                                                    DigitalOcean Employee
                                                                    DigitalOcean Employee badge
                                                                    June 24, 2018

                                                                    Yes, most of them. You can get rid of deep-copy logic if the variables are immutable.

                                                                    - Pankaj

                                                                      JournalDev
                                                                      DigitalOcean Employee
                                                                      DigitalOcean Employee badge
                                                                      August 28, 2018

                                                                      Great Article… very helpful in cracking interviews … Thank you so much !!

                                                                      - Omkar J

                                                                        JournalDev
                                                                        DigitalOcean Employee
                                                                        DigitalOcean Employee badge
                                                                        September 22, 2018

                                                                        Article is very nice and easy to understand. I have gone through the comments and got deeper understanding of this concept. Requesting everyone else to go through the discussions done in comments then you will get more understanding about this topic. Thanks to Pankaj.

                                                                        - Vijay Kumar

                                                                          JournalDev
                                                                          DigitalOcean Employee
                                                                          DigitalOcean Employee badge
                                                                          September 25, 2018

                                                                          This is how we create an immutable class. But can you please describe how the immutable object is created? or is that happens in java or not??

                                                                          - u.mang

                                                                          JournalDev
                                                                          DigitalOcean Employee
                                                                          DigitalOcean Employee badge
                                                                          September 25, 2018

                                                                          A class is a design and Object is the actual implementation. When we say immutable class, it means immutable objects too.

                                                                          - Pankaj

                                                                          JournalDev
                                                                          DigitalOcean Employee
                                                                          DigitalOcean Employee badge
                                                                          April 24, 2021

                                                                          What happens when we have an inner class. How to handle that situation?

                                                                          - janny

                                                                            JournalDev
                                                                            DigitalOcean Employee
                                                                            DigitalOcean Employee badge
                                                                            October 12, 2018

                                                                            Not required map iteration in constructor and return statement clone which you used, may be any other reason please provide that. class Student { private final int sid; private final String sname; private final Map map; public Student(int sid, String sname, Map map) { super(); this.sid = sid; this.sname = sname; this.map = new HashMap(map); //this.list=list; } public int getSid() { return sid; } public String getSname() { return sname; } public Map getList() { return map; } @Override public String toString() { return “Student [sid=” + sid + “, sname=” + sname + “]”; } }

                                                                            - Parvise

                                                                            JournalDev
                                                                            DigitalOcean Employee
                                                                            DigitalOcean Employee badge
                                                                            October 12, 2018

                                                                            Yes, we can use the HashMap constructor too. However, the idea here was to showcase how to perform the deep copy. Not every object constructor provides this feature, in that case, we need to perform field by field copy so that the original object and the cloned object have different references.

                                                                            - Pankaj

                                                                              JournalDev
                                                                              DigitalOcean Employee
                                                                              DigitalOcean Employee badge
                                                                              December 18, 2018

                                                                              Hi, please post your Java code of connection pooling in java without using Spring and hibernate.

                                                                              - Deepak

                                                                                JournalDev
                                                                                DigitalOcean Employee
                                                                                DigitalOcean Employee badge
                                                                                January 3, 2019

                                                                                It was worth a read about immutable class in Java! Really learned a lot form this article. I can imagine the effort you put into this & especially appreciate you sharing it. keep up the good work.

                                                                                - online java training

                                                                                  JournalDev
                                                                                  DigitalOcean Employee
                                                                                  DigitalOcean Employee badge
                                                                                  January 31, 2019

                                                                                  Hi, First i want to thank you for sharing your knowledge with us. here i have one question with this if i am getting HashMap reference through getter method then i can avoid changing Immutable class value by sending deep copy. But what if user accessed it directly? i mean Map local = ce.testMap; local.put(“local” , “local”); in this case ce.testMap will have the above added object as well. How can we avoid this? thanks!

                                                                                  - Pandidurai

                                                                                  JournalDev
                                                                                  DigitalOcean Employee
                                                                                  DigitalOcean Employee badge
                                                                                  February 11, 2019

                                                                                  while returning map return new Object. So the getter method of testMap will look like getTestMap{ return new HashMap(testMap); }

                                                                                  - Rishabh

                                                                                    JournalDev
                                                                                    DigitalOcean Employee
                                                                                    DigitalOcean Employee badge
                                                                                    February 21, 2019

                                                                                    Hi Pandidurai , testMap access is private as rule, so you can not access outside class directly, without getter you can not access directly

                                                                                    - vkas

                                                                                      JournalDev
                                                                                      DigitalOcean Employee
                                                                                      DigitalOcean Employee badge
                                                                                      March 12, 2019

                                                                                      Even within this constructor if you assign cloned version of input “hm” to testMap, it should still work, no need of deep copy. public FinalClassExample(int i, String n, HashMap hm){ System.out.println(“Performing Shallow Copy for Object initialization”); this.id=i; this.name=n; this.testMap=hm.clone(); }

                                                                                      - Ravi Beli

                                                                                      JournalDev
                                                                                      DigitalOcean Employee
                                                                                      DigitalOcean Employee badge
                                                                                      March 18, 2019

                                                                                      Perfect answer with a small change. You need to type cast when calling the clone method as it return object.

                                                                                      - Satish

                                                                                        JournalDev
                                                                                        DigitalOcean Employee
                                                                                        DigitalOcean Employee badge
                                                                                        April 12, 2019

                                                                                        What’s the significance of declaring class as final here?

                                                                                        - Ashwani Pratap

                                                                                        JournalDev
                                                                                        DigitalOcean Employee
                                                                                        DigitalOcean Employee badge
                                                                                        April 14, 2019

                                                                                        So that it can’t be extended.

                                                                                        - Pankaj

                                                                                          JournalDev
                                                                                          DigitalOcean Employee
                                                                                          DigitalOcean Employee badge
                                                                                          May 19, 2019

                                                                                          But when we trying to change a String object a new object would be created with those changes. Is that possible here ?. Please explain

                                                                                          - Sreerag

                                                                                            JournalDev
                                                                                            DigitalOcean Employee
                                                                                            DigitalOcean Employee badge
                                                                                            July 21, 2019

                                                                                            One of the best example and explanation for “creating immutable class”. Loved it. Thanks !!

                                                                                            - Mukund Padale

                                                                                              JournalDev
                                                                                              DigitalOcean Employee
                                                                                              DigitalOcean Employee badge
                                                                                              August 10, 2019

                                                                                              4. Make all mutable fields final so that it’s value can be assigned only once. I don’t think this is necessary if are declaring the fields private. mutable fields marked as final can still be mutated, only the reference can not be changed.

                                                                                              - Manohar Bhat

                                                                                              JournalDev
                                                                                              DigitalOcean Employee
                                                                                              DigitalOcean Employee badge
                                                                                              January 14, 2020

                                                                                              Afaik private modifier doesn’t help against reflection. Final does

                                                                                              - Bartosz Wyględacz

                                                                                                JournalDev
                                                                                                DigitalOcean Employee
                                                                                                DigitalOcean Employee badge
                                                                                                August 31, 2019

                                                                                                What about Date variable we can still change the date by writing d.getTime(); How can we avoid that?

                                                                                                - jogi

                                                                                                JournalDev
                                                                                                DigitalOcean Employee
                                                                                                DigitalOcean Employee badge
                                                                                                October 9, 2019

                                                                                                public final class Sample { private final Date dateField; //Default private constructor will ensure no unplanned construction of class private Sample(Date date) { this.dateField = new Date(date.getTime()); } /** * Date class is mutable, so we need a little care here. * We should not return the reference of original instance variable. * Instead of a new Date object, with content copied to it, should be returned. * */ public Date getDateField() { return new Date(dateField.getTime()); } }

                                                                                                - Jerome

                                                                                                  JournalDev
                                                                                                  DigitalOcean Employee
                                                                                                  DigitalOcean Employee badge
                                                                                                  November 7, 2019

                                                                                                  Hi Pankaj, I have been following your site for quite some time & it has been helping me a lot… Thank you very much for that. Just one suggestion, the “scrollable” code blocks are not very user-friendly to use. It would be great if we can see the entire code at once - even though it increases the height of the page, just my personal experience…

                                                                                                  - Shobhit Mittal

                                                                                                    JournalDev
                                                                                                    DigitalOcean Employee
                                                                                                    DigitalOcean Employee badge
                                                                                                    November 22, 2019

                                                                                                    hi Pankaj, great work !!! what is the need of getter method HashMap clone as we are constructing deep clone object? thanks Aravind Sundarraj

                                                                                                    - Aravind Sundarraj

                                                                                                    JournalDev
                                                                                                    DigitalOcean Employee
                                                                                                    DigitalOcean Employee badge
                                                                                                    November 10, 2020

                                                                                                    Hi Aravind , If we don’t do a getter method Clone , then we will be sending the Original object reference without making any copy in the memory . So that original object reference can be easily modified after fetching it from getter method. If you return the HashMap like below , even after deep clone in constructor that we can modify the original object public HashMap getTestMap() { return testMap; } System.out.println(“ce testMap:”+ce.getTestMap()); h= ce.getTestMap(); h.put(“3”,“three”); System.out.println("ce testMap after accessor method cahnges "+ce.getTestMap());

                                                                                                    - Divya

                                                                                                      JournalDev
                                                                                                      DigitalOcean Employee
                                                                                                      DigitalOcean Employee badge
                                                                                                      December 2, 2019

                                                                                                      Hi, its Explained very nicely, I have one question like i have 2 classes as below. class Separtment{ int id, String name; } Class Employee{ Department Dept, int id, String name; } Here i want to make Employee as immutable, but here Department is a child object, so here how come i make Employee class is immutable. Also One constraint like the Department object which I won’t own(I am not allowed to change anything in the Department object).

                                                                                                      - Akhil Kumar Patro

                                                                                                      JournalDev
                                                                                                      DigitalOcean Employee
                                                                                                      DigitalOcean Employee badge
                                                                                                      December 29, 2019

                                                                                                      As shown in example, first you must add modifiers(private & final) for every variable. While adding getDept(); you must return clone() object as shown in example as testMap. while writing constructor instead of assigning directly take a temporary dept variable and populate and assign to the main this.dept variable(not direct variable, dublicate variable you have to do).

                                                                                                      - Kalyan Gudla

                                                                                                        JournalDev
                                                                                                        DigitalOcean Employee
                                                                                                        DigitalOcean Employee badge
                                                                                                        July 31, 2020

                                                                                                        HI Pankaj, I tried your code and analysed that by only returning the map.clone() object will work here no need to make deep copy in constructor.

                                                                                                        - Lokesh Kumar

                                                                                                        JournalDev
                                                                                                        DigitalOcean Employee
                                                                                                        DigitalOcean Employee badge
                                                                                                        November 10, 2020

                                                                                                        Hi Lokesh, If you don’t make a deep copy in the constructor and just do a map.clone() alone , then the changes for local map in the main method will affect the Final class map . Try this with Shallow copy , you will understand better public static void main(String[] args) { HashMap h1 = new HashMap(); h1.put(“1”, “first”); h1.put(“2”, “second”); String s = “original”; int i=10; FinalClassExample ce = new FinalClassExample(i,s,h1); System.out.println(“ce testMap:”+ce.getTestMap()); h1.put(“3”,“Third”); System.out.println(“ce testMap after local variable change:”+ce.getTestMap()); }

                                                                                                        - Divya

                                                                                                          JournalDev
                                                                                                          DigitalOcean Employee
                                                                                                          DigitalOcean Employee badge
                                                                                                          June 14, 2021

                                                                                                          I believe deep copy will be needed for ID and Name as well. Please explain if not.

                                                                                                          - Dinesh Solanki

                                                                                                            JournalDev
                                                                                                            DigitalOcean Employee
                                                                                                            DigitalOcean Employee badge
                                                                                                            December 30, 2021

                                                                                                            who can solve this for me? /* Edit the code by following the steps in the description */ import java.util.HashMap; import java.util.Map; public class Location { final int locationID; public String description; protected Map exits; public Location(int locationID, String description, Map exits) { this.locationID = locationID; this.description = description; this.exits = new HashMap(exits); this.exits.put(“Q”, 0); } public void addExit(String direction, int location) { exits.put(direction, location); } public void setLocationID(int locationID) { this.locationID = locationID; } public int getLocationID() { return locationID; } public void setDescription(String description) { this.description = description; } public String getDescription() { return description; } public void setExits(Map exits) { this.exits = exits; } public Map getExits() { return exits; } } Make the Location class an Immutable Class. The strategy for creating an Immutable Class is:     Steps:     1. Don’t provide setters.     2. Make all fields final and private     3. Don’t allow the class to be subclassed.     4. If the instance fields include references to mutable objects, don’t allow those objects to be changed:                -  Don’t provide methods that modify the mutable objects.             -  Don’t share references to the mutable objects. As an added Task, handle the case where exits is null when passed to the constructor. NOTE: Not all classes documented as “immutable” follow these rules. However, the steps above are the basis of an Immutable Class.

                                                                                                            - Francis

                                                                                                              Try DigitalOcean for free

                                                                                                              Click below to sign up and get $200 of credit to try our products over 60 days!

                                                                                                              Sign up

                                                                                                              Join the Tech Talk
                                                                                                              Success! Thank you! Please check your email for further details.

                                                                                                              Please complete your information!

                                                                                                              Become a contributor for community

                                                                                                              Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

                                                                                                              DigitalOcean Documentation

                                                                                                              Full documentation for every DigitalOcean product.

                                                                                                              Resources for startups and SMBs

                                                                                                              The Wave has everything you need to know about building a business, from raising funding to marketing your product.

                                                                                                              Get our newsletter

                                                                                                              Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

                                                                                                              New accounts only. By submitting your email you agree to our Privacy Policy

                                                                                                              The developer cloud

                                                                                                              Scale up as you grow — whether you're running one virtual machine or ten thousand.

                                                                                                              Get started for free

                                                                                                              Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

                                                                                                              *This promotional offer applies to new accounts only.