如果你不标记类,我可能会突然把你看似不可变的类变成可变的。例如,请考虑以下代码:final
public class Immutable {
private final int value;
public Immutable(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
现在,假设我执行以下操作:
public class Mutable extends Immutable {
private int realValue;
public Mutable(int value) {
super(value);
realValue = value;
}
public int getValue() {
return realValue;
}
public void setValue(int newValue) {
realValue = newValue;
}
public static void main(String[] arg){
Mutable obj = new Mutable(4);
Immutable immObj = (Immutable)obj;
System.out.println(immObj.getValue());
obj.setValue(8);
System.out.println(immObj.getValue());
}
}
请注意,在我的子类中,我已覆盖读取子类中声明的新可变字段的行为。因此,您的类(最初看起来不可变)实际上并不是不可变的。我可以将此对象传递到任何预期的对象,这可能会对代码造成非常糟糕的事情,假设该对象确实是不可变的。标记基类可防止这种情况发生。Mutable
getValue
Mutable
Immutable
final
希望这有帮助!
与许多人所认为的相反,制作一个不可变的类并不是必需的。final
创建不可变类的标准参数是,如果不这样做,则子类可以添加可变性,从而违反超类的协定。该类的客户端将假定不可变性,但是当某些东西从它们下面变异出来时,他们会感到惊讶。final
如果你把这个参数带到它的逻辑极端,那么所有的方法都应该被提出来,否则子类可能会以不符合其超类契约的方式覆盖一个方法。有趣的是,大多数Java程序员认为这是荒谬的,但不知何故,他们对不可变类应该是的想法是可以接受的。我怀疑这与Java程序员通常对不可变性的概念并不完全满意有关,也许是与Java中关键字的多种含义有关的某种模糊思维。final
final
final
遵守超类的契约不是编译器可以或应该始终强制执行的。编译器可以强制执行协定的某些方面(例如:一组最小方法及其类型签名),但编译器无法强制执行典型协定的许多部分。
不可变性是类协定的一部分。这与人们更习惯的一些事情有点不同,因为它说明了类(以及所有子类)不能做什么,而我认为大多数Java(通常是OOP)程序员倾向于认为契约与类可以做什么有关,而不是它不能做什么。
不可变性还影响的不仅仅是单个方法 -它会影响整个实例 - 但这与 Java 的工作方式和工作方式并没有太大区别。这两种方法在 中列出了特定的合同。该合同非常仔细地列出了这些方法无法做到的事情。此合约在子类中更具体。很容易覆盖或以违反合同的方式覆盖。实际上,如果您只覆盖这两种方法中的一种而没有另一种方法,则很可能违反了合同。那么应该并且已经宣布以避免这种情况吗?我想大多数人会争辩说他们不应该。同样,也没有必要创建不可变的类 。equals
hashCode
Object
equals
hashCode
equals
hashCode
final
Object
final
也就是说,您的大多数类,无论是否可变,可能都应该是 .请参阅《有效的 Java 第二版》第 17 项:“用于继承的设计和文档,否则将禁止继承”。final
因此,步骤 3 的正确版本是:“使类成为最终类,或者在设计子类化时,清楚地记录所有子类必须继续是不可变的。
-
如何在java中使对象不可变 由于这是当今的热门话题,我无法理解某些概念。请原谅我,如果我听起来很愚蠢,但当我尝试创建不可变对象时,我发现大多数帖子我都发现以下几点 使课程最终 - 有意义 不允许属性的赋值
-
为什么后增量在包装器类上起作用 我正在对一些代码进行审查,并遇到了一个实例,有人在递增一个成员变量后,该成员变量是围绕整数的包装类。我自己尝试了一下,真的很惊讶它的工作原理。 但显然,规范中有一些东西使
-
-
-
为什么整数在Java中是不可变的? 我知道整数在Java中是不可变的。但是为什么它是这样设计的呢? 在问这个问题之前,我浏览了其他答案: 的这句话 可以缓存。 其他人正在减少全局状态 更易于多线程处理