简体   繁体   中英

Is it possible to do a final class immutable in Java?

Recently on the interview I had an interesting question. We have mutable class:

final class Example {
  private int i;
  private String s;
  private Object o;
  // get, set
}

And instance of this class Example e = new Example();

Can we somehow make this instance immutable? Without changing original class.

My thoughts:

  1. Deep cloning of this instance? But not sure if it's possible.
  2. Maybe something like serialization/deserialization?

If you are unable to make modifications to the Example class and you cannot subclass it (in your snippet, it is marked as final ) the closest solution I can think of is to create a wrapper class, which is immutable. This is not a perfect solution, and has it's drawbacks.

First, how to do it:

final class ImmutableExample {
  // Redeclare every field as in the Example class
  // but make sure they can't be reassigned 
  // (in this case I'll declare them as final)
  private final int i;
  private final String s;
  private final Object o;

  ImmutableExample(Example mutableExample) {
      // copy fields from original
      this.i = mutableExample.getI();
      this.s = mutableExample.getS();
      this.o = mutableExample.getO();
  }

  // add getters but definitely no setters
}

Then everywhere you have code like this:

Example e = new Example();
e.setI(42); // etc

Change to:

Example e = new Example();
e.setI(42); // etc
ImmutableExample immutableE = new ImmutableExample(e);

And pass around references to immutableE , and make sure that the e reference does not escape.

Now, for the drawbacks:

  • ImmutableExample is not an instance of Example , so you cannot pass the immutable type to a method which expects the mutable type, and operations like if (immutableE instanceof Example) or (Example)immutableE will not work as before

  • You have to be very careful that every field of Example is also immutable, or ImmutableExample will also be mutable. Consider, for example, that the field of type Object could be something mutable, like a HashMap or a Date .

  • When the Example class changes, you have to repeat the change in ImmutableExample .

If it was possible to subclass Example , or if it was an interface, this approach might be more useful, but I can't see any other way when Example cannot be subclassed.

If each of those fields have getters/setters, then to make it immutable, you will have to

  1. Make each field private and final
  2. Make a copy of each field when it's getter is called
  3. Remove all setters
  4. Any methods within the class that changes it's state must either be removed or use the new getters to access any internals

Immutability is a property of a class not an instance. So besides bytecode twiddling or other means to change the class; not possible.

With a none final class i would create an immutable decorator. That would not make the instance immutable, but provide an immutable wrapper to that instance.

You could not assign the instance to any variable/field, making it impossible to change it ;)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM