简体   繁体   English

是否可以在Java中完成不可变的最终类?

[英]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(); 此类的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. 如果您无法进行修改的Example你不能继承它(在你的代码片段,它被标记为final )我能想到的最接近的解决方案是创建一个包装类,这是不可改变的。 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. 并传递对immutableE引用,并确保e引用不会转义。

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 ImmutableExample不是Example ,因此您不能将不可变类型传递给需要可变类型的方法,并且if (immutableE instanceof Example)(Example)immutableE将无法像以前那样工作

  • You have to be very careful that every field of Example is also immutable, or ImmutableExample will also be mutable. 您必须非常小心, Example每个字段也是不可变的,否则ImmutableExample也是可变的。 Consider, for example, that the field of type Object could be something mutable, like a HashMap or a Date . 例如,考虑类型为Object的字段可以是可变的,例如HashMapDate

  • When the Example class changes, you have to repeat the change in ImmutableExample . Example类更改时,必须在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. 如果可以将Example子类化,或者如果它是一个接口,则此方法可能更有用,但是在不能对Example子类化时,我看不到任何其他方式。

If each of those fields have getters/setters, then to make it immutable, you will have to 如果每个字段都有getter / setter,那么要使其不可变,您将必须

  1. Make each field private and final 将每个字段设为privatefinal
  2. Make a copy of each field when it's getter is called 调用getter时复制每个字段
  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 类中任何更改其状态的方法都必须删除或使用新的getter来访问任何内部方法

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 ;) 您无法将实例分配给任何变量/字段,因此无法更改它;)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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