Is a Java Immutable Class Always final?

1 2 Page 2
Page 2 of 2

The output shown above demonstrates how a subclass can misrepresent its parent's advertised behavior. This can happen anytime implementation inheritance is involved, but it is more insidious when we have reason to believe the class involved is immutable. We could mark the methods as final to reduce much of this, but the constructor still has issues. Furthermore, marking all the parent class's methods as final rather than simply marking the entire class as final has some drawbacks. These include the potential conundrum about how to handle methods (such as toString()) that really should not be final and the risk of new methods being added to the parent class without the developer remembering or knowing to mark them as final.

In the DemonstrationMain class, I also made use of a custom class called RenegadeBigDecimal. The purpose of this class is to demonstrate the abuse of a subclass of BigDecimal. The code listing for RenegadeBigDecimal is shown next.

RenegadeBigDecimal.java

package dustin.examples;

import java.math.BigDecimal;

/**
 * Demonstrating the troubles with non-final 'immutable' classes.
 */
public class RenegadeBigDecimal extends BigDecimal
{
   /**
    * Parameterized constructor accepting Long for instantiation of BigDecimal.
    *
    * @param val Long parameter intended, but not actually used, for
    *    instantiation of BigDecimal.
    */
   public RenegadeBigDecimal(final Long val)
   {
      super(-1);
   }

   /**
    * Example of intentionally abusing behavior likely expected for an
    * immutable class by the subclass.
    *
    * @param divisor Divisor in division process.
    */
   public BigDecimal divide(final BigDecimal divisor)
   {
      return this;
   }
}

This last example shows how easy it is to abuse BigDecimal. Because the divide method was overridden to return itself, it is obvious that neither the BigDecimal class nor its method divide were designated as final. Even if the divide method would have been made final, the constructor could still have implemented bad intent and any client code thinking it was a BigDecimal would pay the consequences.

Trade-offs and Drawbacks of final Immutable Classes

There may be times when the ability to override a "largely immutable" or "mostly immutable" class is more important than having a "completely immutable" or "strongly immutable" class. Software design and development is full of trade-offs and this is just another one of those. The benefits of different degrees of mutability can be weighed against the costs. I believe it is no coincidence that Joshua Bloch changed the title of his Effective Java item on immutable objects from "Favor Immutability" in Edition 1 to "Minimize Mutability" in Edition 2. I think this is most readily done by starting with a class that is completely or strongly immutable and only relaxing its mutability in different ways when justified by the benefits of doing so.

Again, at least in my mind, it is no coincidence that the creators of the recently announced Noop project have stated that they wish to encourage immutability and that they wish to discourage implementation inheritance. I think in many of the cases in which implementation inheritance might be desired, it might be better to simply use composition to share common, immutable data and behaviors between two highly related, possibly immutable, classes. That advice doesn't sound particularly different than what many others have suggested before in terms of all classes, including mutable classes.

Conclusion

The safest way to make a class "strongly immutable" is to designate the entire class as final. Doing so ensures that no mistakes will be made in creating new methods in the future in the immutable class that are not marked final and can be carelessly or maliciously overridden. The final keyword applied at class level also prevents subclasses from "masquerading" as their immutable parent with very different behavior than that expected for the "immutable" parent class.

Additional References

Mutable and Immutable Objects

Making a Class Immutable

⇒ StackOverflow: immutable class should be final?

OBJ38-J: Immutable Classes Must Prohibit Extension

Bug 4617197 - RFE: Add Immutable types to Java

Immutable Objects in Java

Some Concurrency Tips (talks about benefits of immutable objects)

The Final Word on the final Keyword

This story, "Is a Java Immutable Class Always final?" was originally published by JavaWorld.

Copyright © 2009 IDG Communications, Inc.

1 2 Page 2
Page 2 of 2
How to choose a low-code development platform