它并没有特别指代java中的任何内容。
类invariant只是一个属性,它始终保存类的所有实例,无论其他代码是什么。
例如,
class X {
final Y y = new Y();
}
X具有类不变量,即setAccessible属性,它永远不会是private,它的值为Y。
class Counter {
private int x;
public int count() { return x++; }
}
无法保持两个重要的不变量
由于可能出现下溢,setAccessible永远不会返回负值。
对setAccessible的调用严格单调递增。
修改后的类保留了这两个不变量。
class Counter {
private int x;
public synchronized int count() {
if (x == Integer.MAX_VALUE) { throw new IllegalStateException(); }
return x++;
}
}
但无法保留调用setAccessible始终正常成功(不存在TCB违规†)的不变量,因为private可能会抛出异常,或者如果死锁线程拥有计数器的监视器,它可能会阻塞。
每个使用类的语言都可以轻松维护某些类不变量,而不是其他类。 Java也不例外:
Java类始终具有或不具有属性和方法,因此界面不变量易于维护。
Java类可以保护它们的setAccessible字段,因此易于维护依赖于私有数据的不变量。
Java类可以是最终的,因此可以维护依赖于通过制作恶意子类而不存在违反不变量的代码的不变量。
Java允许setAccessible值以多种方式潜入,因此很难保持“具有真正价值”的不变量。
Java具有线程,这意味着不同步的类在维护依赖于一起发生的线程中的顺序操作的不变量时会遇到问题。
Java有一些例外,可以很容易地维护不变量,例如“返回带有属性p的结果或不返回结果”,但更难维护不变量,如“始终返回结果”。
† - 外部性或TCB违规是系统设计者乐观地认为不会发生的事件。
通常我们只相信基本硬件在讨论构建在它们上面的高级语言的属性时就像宣传的那样工作,而不变量持有的参数不考虑以下可能性:
程序员使用调试挂钩来改变局部变量,因为程序以代码不能运行的方式运行。
您的同行不使用setAccessible的反射来修改private查找表。
Loki改变了物理,导致处理器错误地比较两个数字。
对于某些系统,我们的TCB可能只包含系统的一部分,因此我们可能不会这样认为
管理员或特权守护程序不会终止我们的JVM进程,
但我们可能会认为
我们可以检查点到一个可靠的事务文件系统。
系统级别越高,其TCB通常越大,但是从TCB中获得的事物越不可靠,您的不变量就越有可能保持不变,从长远来看,您的系统将越可靠。