Java中的所有最终类都是不可变的。String 和 Integer 都是最终类,我相信它们都是不可变的。
8 回答
不,final 意味着类不能扩展。它没有提到可变性。例如:
final class MutInt {
public int modifyMe;
}
不——最终类意味着你不能从它继承。它与可变性无关。以下类是最终的但可变的:
public final class FinalMutable {
int value;
public void setValue(int v) { value=v; }
public int getValue() { return value; }
}
不变性没有关键字,它更像是一种设计模式。
编辑:
这意味着,没有关键字使类不可变。要使类不可变,您必须通过使它们成为最终或私有来保护内部。
令人困惑的是:final 关键字在用于类时与在字段/变量上使用时具有不同的含义。前者的意思是“这个类不能扩展”。第二个意思是“这个变量(或引用)不能改变”。
除了其他响应之外,如果您查看代码,java.lang.String
您会看到它包含一个字段:hash
,该字段是可变的,实际上hashCode()
是在第一次调用时计算和存储的。
但是,该类仍然是不可变的:该hash
字段不能在类之外直接访问或修改。
此外,您可能会注意到 JDK 中的一种常见方法是实现不可变包装器,该包装器可用于公开对象的内部状态而不允许对其进行修改;例如
private final List<String> values;
public List<? get String> getValues() {
return Collections.unmodifiableList(values);
}
正如其他人之前所说的final
那样,尽管它在不变性策略中发挥了作用,但它并没有使 Java 中的类成为不可变的。要获得不变性,您应该遵循一般准则:
- 确保类不能被覆盖-创建类
final
,或使用静态工厂并保持构造函数私有 - 制作字段
private
和final
- 强制调用者在一个步骤中完全构造一个对象,而不是使用无参数构造函数与对
setXXX
方法的后续调用相结合(即避免 Java Beans 约定) - 不提供任何可以以任何方式改变对象状态的方法——不仅仅是
setXXX
方法,而是任何可以改变状态的方法 - 如果类有任何可变对象字段,那么当在类和它的调用者之间传递时,它们必须被防御性地复制
子类的重写方法无法访问私有字段……所以子类方法无法更改超类的私有字段……那么将不可变类设为final有什么用?
final 关键字防止其他类继承它。Final 关键字不会使其不可变,但有这样的条件,例如使实例类成员私有以及 final 以及使用 getter 而不是使用 setter
最终的不可变类不能被变异。下面它显示了一个正在变异的非最终不可变类:
// a class not intended to be mutated
public class GoodClass{
private String name;
public GoodClass() {
this.name = "Good Class Neme";
}
public String getName() {
return name;
}
}
public class BadClass extends GoodClass {
private String name;
public String getName() {
return name;
}
// mutating state
public void setName(String name) {
this.name = name;
}
}