Java中的类不变量是什么?

2022-08-31 10:14:04

我用谷歌搜索了这个话题,但除了维基百科,我没有找到任何进一步的有用文档或文章。

任何人都可以用简单的语言向我解释它的含义,或者向我推荐一些漂亮且易于理解的文档吗?


答案 1

在Java中,它没有任何特别的含义。

类不变量只是一个属性,它始终对类的所有实例都有效,无论其他代码如何操作。

例如

class X {
  final Y y = new Y();
}

X 具有类不变性,即存在一个属性,并且它从不,并且它具有类型 。ynullY

class Counter {
  private int x;

  public int count() { return x++; }
}

这未能维护两个重要的不变量:

  1. 这永远不会返回负值,因为可能下溢。count
  2. 这种呼吁严格地单调地增加。count

修改后的类保留这两个不变量。

class Counter {
  private int x;

  public synchronized int count() {
    if (x == Integer.MAX_VALUE) { throw new IllegalStateException(); }
    return x++;
  }
}

...但无法保留调用始终正常运行的不变量(不存在 TCB 违规†),因为如果死锁线程拥有计数器的监视器则可能会引发异常或阻塞。countcount

每门带有类的语言都可以轻松维护某些类不变量,但不能维护其他类不变量。Java也不例外:

  1. Java 类始终具有或没有属性和方法,因此接口不变量易于维护。
  2. Java 类可以保护它们的字段,因此依赖于私有数据的不变量很容易维护。private
  3. Java 类可以是最终的,因此可以维护依赖于没有代码通过手工创建恶意子类来违反不变量的不变量。
  4. Java允许值以多种方式潜入,因此很难维护“具有实际值”的不变量。null
  5. Java具有线程,这意味着不同步的类在维护依赖于线程中一起发生的顺序操作的不变量时会遇到麻烦。
  6. Java有例外,这使得维护不变量变得容易,例如“返回具有属性p的结果或不返回任何结果”,但更难维护不变量,例如“始终返回结果”。

† - 外部性TCB违规是系统设计人员乐观地认为不会发生的事件。

通常,我们只是相信基本硬件在谈论基于它们构建的高级语言的属性时所宣传的那样工作,并且我们的不变量持有的论点没有考虑到以下可能性:

  • 程序员使用调试钩子来更改局部变量,因为程序以代码无法运行的方式运行。
  • 您的对等方不使用反射来修改查找表。setAccessibleprivate
  • Loki改变物理特性,导致处理器错误地比较两个数字。

对于某些系统,我们的TCB可能只包括系统的一部分,因此我们可能不会假设

  • 管理员或特权守护程序不会杀死我们的JVM进程,

...但我们可以假设:

  • 我们可以检查点到一个可靠的事务性文件系统。

系统级别越高,其TCB通常越大,但是您可以从TCB中获得的不可靠的东西越多,您的不变量就越有可能成立,从长远来看,您的系统就越可靠。


答案 2

不变性意味着无论发生什么变化或谁使用它/转换它,都应该坚持其条件。也就是说,类的属性总是满足或满足某些条件,即使在使用公共方法进行转换之后也是如此。因此,可以确保此类的客户端或用户了解该类及其属性。

例如

  1. 函数参数的条件是,它应该始终> 0(大于零)或不应为 null。
  2. Minimum_account_balance帐户类的属性状态,则它不能低于 100。因此,所有公共函数都应遵守此条件并确保类不变。
  3. 变量之间基于规则的依赖关系,即一个变量的值依赖于另一个变量,因此,如果一个变量发生更改,则使用某些修复规则,另一个变量也必须更改。必须保留 2 个变量之间的这种关系。否则,则违反不变性。