首页 归档 关于 learn love 工具

Mutable and Immutable Objects

Mutable Objects: When you have a reference to an instance of an object, the contents of that instance can be altered
Immutable Objects: When you have a reference to an instance of an object, the contents of that instance cannot be altered

Building an Immutable class

Fields must be private

Obviously all of the fields must be private. There is little point removing the mutators if they aren't even required to change the instance contents.

Make sure methods can't be overridden.

If your class gets extended, it could add extra fields that are not immutable, or the methods could be overridden to return a different value each time. There are two ways to protect against this.

  • The preferred way is to make the class final. This is sometimes referred to as "Strong Immutability". It prevents anyone from extending your class and accidentally or deliberately making it mutable.

  • The second way, also called "Weak Immutability" is to make your methods final. It allows others to extend your class to add more behaviour, but protects the original contract specified by the class. If you want a more verbose description, imagine a class A is weakly immutable. If you have an instance of object A, it is immutable. If someone creates class B that extends A, it is only the behaviour defined by the A class that is immutable. Any added behaviour from class B may not be immutable.

Protect mutable fields

The last requirement which many people fall victim too, is to build your immutable class from primitive types or immutable fields, otherwise you have to protect mutable fields from manipulation.
To highlight this problem, we'll use the example of a supposedly immutable class representing a person. Our class has a first and last name, as well as a date of birth.

import java.util.Date;
public final class BrokenPerson
	{
		private String firstName;
		private String lastName;
		private Date dob;

		public BrokenPerson( String firstName,
		  String lastName, Date dob)
		{
			this.firstName = firstName;
			this.lastName = lastName;
			this.dob = dob;
		}

		public String getFirstName()
		{
			return this.firstName;
		}
		public String getLastName()
		{
			return this.lastName;
		}
		public Date getDOB()
		{
			return this.dob;
		}
	}

This all looks fine, until someone uses it like this:

    Date myDate = new Date();
	BrokenPerson myPerson =   new BrokenPerson( "David", "O'Meara", myDate );
	System.out.println( myPerson.getDOB() );
	myDate.setMonth( myDate.getMonth() + 1 );
	System.out.println( myPerson.getDOB() );

Our Template for Immutable Classes

Now we have a template for creating immutable objects.

  • Make all fields private
  • Don't provide mutators
  • Ensure that methods can't be overridden by either making the class final (Strong Immutability) or making your methods final (Weak Immutability)
  • If a field isn't primitive or immutable, make a deep clone on the way in and the way out.

Which classes are Immutable?

To finish up, lets discuss the common Java classes that are immutable and those that aren't. Firstly, all of the java.lang package wrapper classes are immutable: Boolean, Byte, Character, Double, Float, Integer, Long, Short, String.
As in the Person classes we discussed, java.util.Date objects are not immutable. The classes java.math.BigInteger and BigDecimal are not immutable either, although maybe they should have been.

source

https://javaranch.com/journal/2003/04/immutable.htm