最近在采访中我提出了一个有趣的问题。 我们有可变类:
if let loggedIn = result?["loggedIn"] as? String where loggedIn == "1" { ...
此类的实例final class Example {
private int i;
private String s;
private Object o;
// get, set
}
我们可以以某种方式使这个实例不可变吗?不改变原班级。
我的想法:
答案 0 :(得分:2)
如果您无法修改Example
类和,则无法对其进行子类化(在您的代码段中,标记为final
),我可以使用最接近的解决方案想到的是创建一个包装类,它是不可变的。这不是一个完美的解决方案,并且有它的缺点。
首先,如何做到:
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
}
然后到处都有这样的代码:
Example e = new Example();
e.setI(42); // etc
更改为:
Example e = new Example();
e.setI(42); // etc
ImmutableExample immutableE = new ImmutableExample(e);
并传递对immutableE
的引用,并确保e
引用不会转义。
现在,出于缺点:
ImmutableExample
不是Example
的实例,因此您无法将不可变类型传递给期望可变类型的方法,以及if (immutableE instanceof Example)
或{{1}等操作不会像以前一样工作
您必须非常小心,(Example)immutableE
的每个字段也是不可变的,或Example
也是可变的。例如,请考虑ImmutableExample
类型的字段可能是可变的,例如Object
或HashMap
。
当Date
班级发生变化时,您必须重复Example
中的更改。
如果可以继承ImmutableExample
,或者它是一个接口,这种方法可能更有用,但是当Example
无法被子类化时,我无法看到任何其他方式。
答案 1 :(得分:0)
如果每个字段都有getter / setter,那么为了使它不可变,你将不得不
private
和final
答案 2 :(得分:0)
不变性是一个类的属性,而不是一个实例。所以除了字节码twiddling或其他方式改变类;不可能。
如果没有最终类,我会创建一个不可变的装饰器。这不会使实例成为不可变的,而是为该实例提供一个不可变的包装器。
您无法将实例分配给任何变量/字段,因此无法更改它;)