Java中的类不变量是什么?

Java中的类不变量是什么?,java,terminology,invariants,Java,Terminology,Invariants,我在谷歌上搜索了这个主题,但除此之外,我没有找到任何有用的文档或文章 有谁能用简单的语言向我解释一下它的意思,或者让我参考一些好的、易于理解的文档吗?关于实例类,这些都是事实。例如,如果一个类有一个属性X且不变量可以是X,则X必须大于0。据我所知,没有内置的方法来维护不变性,您必须将属性设置为私有,并确保getter和setter强制执行不变性属性 有一些注释可以使用反射和拦截器检查属性。 对于Java来说,它并没有什么特别的含义 类不变量只是一个属性,它始终适用于类的所有实例,而不管其他代码执

我在谷歌上搜索了这个主题,但除此之外,我没有找到任何有用的文档或文章


有谁能用简单的语言向我解释一下它的意思,或者让我参考一些好的、易于理解的文档吗?

关于实例类,这些都是事实。例如,如果一个类有一个属性X且不变量可以是X,则X必须大于0。据我所知,没有内置的方法来维护不变性,您必须将属性设置为私有,并确保getter和setter强制执行不变性属性

有一些注释可以使用反射和拦截器检查属性。

对于Java来说,它并没有什么特别的含义

类不变量只是一个属性,它始终适用于类的所有实例,而不管其他代码执行什么操作

比如说,

class X {
  final Y y = new Y();
}
X具有类不变量,即存在一个
y
属性,它从不
null
,并且它的值类型为
y

class Counter {
  private int x;

  public int count() { return x++; }
}
这无法保持两个重要的不变量:

  • 由于可能的下溢,该
    count
    从不返回负值
  • count
    的调用是严格单调递增的
  • 修改后的类保留这两个不变量

    class Counter {
      private int x;
    
      public synchronized int count() {
        if (x == Integer.MAX_VALUE) { throw new IllegalStateException(); }
        return x++;
      }
    }
    
    …但无法保留调用
    count
    始终正常成功(不存在TCB冲突†)的不变量,因为
    count
    可能引发异常,或者如果死锁线程拥有计数器的监视器,它可能会阻塞

    每种带有类的语言都可以很容易地维护某些类不变量,但不能维护其他类不变量。Java也不例外:

  • Java类始终具有或不具有属性和方法,因此接口不变量易于维护
  • Java类可以保护它们的
    private
    字段,因此依赖于私有数据的不变量很容易维护
  • Java类可以是最终类,因此可以维护依赖于不存在通过创建恶意子类而违反不变量的代码的不变量
  • Java允许
    null
    值以多种方式潜入,因此很难维护“has a real value”不变量
  • Java有线程,这意味着不同步的类很难维护依赖于线程中同时发生的顺序操作的不变量
  • Java有一些例外情况,这使得维护诸如“返回带有属性p的结果或不返回结果”之类的不变量变得容易,但维护诸如“总是返回结果”之类的不变量则更难

  • †-外部性或违规是系统设计师乐观地认为不会发生的事件

    通常,我们只相信基本硬件在谈论构建在其上的高级语言的属性时会像广告中所宣传的那样工作,而不变量所持的论点没有考虑到以下可能性:

    • 当程序以代码无法实现的方式运行时,程序员使用调试挂钩改变局部变量
    • 您的同龄人不会将反射与
      setAccessible
      一起使用来修改
      private
      查找表
    • 洛基改变物理导致处理器错误地比较两个数字
    对于某些系统,我们的TCB可能只包括系统的一部分,因此我们可能不会假设

    • 管理员或特权守护进程不会杀死我们的JVM进程
    …但我们可以假设:

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

    a级系统越高,其TCB通常越大,但从TCB中得到的东西越不可靠,不变量就越有可能保持不变,从长远来看,您的系统将更加可靠。

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

    比如说,

    class X {
      final Y y = new Y();
    }
    
  • 函数参数的条件是,它应始终大于0(大于零)或不应为null
  • 帐户类的最小帐户余额属性声明,它不能低于100。所以所有的公共函数都应该尊重这个条件并确保类不变
  • 变量之间基于规则的依赖关系,即一个变量的值取决于另一个变量的值,因此如果一个变量发生更改,使用某些修复规则,另一个变量也必须更改。必须保留两个变量之间的这种关系。如果没有,则违反不变量

  • +因为维基百科页面有一个非常好的例子,我不知道你能做什么,它甚至有一些例子。他们的解释比我能为你做的更好;这很简单。如果你对不变量w.r.t.Java感兴趣,也许你会感兴趣。一个更简单的解释是,“计数从不两次返回相同的值”真的被认为是类不变量吗?@ruakh,这是个好问题。我不太确定。像hashCode稳定性(对于每个实例i,i.hashCode()不改变)这样的东西通常被称为类不变量,这需要对以前返回的值进行推理,所以说“对于每个实例i,i.count()不在(i.count()以前的结果)中”是类不变量似乎是合理的。@ruakh这不是一个纯粹的定义吗?如果我假设这样一个不变量,为什么不呢?这当然是一个有趣而重要的保证(比如生成唯一ID)。我个人也认为“如果只有单线程代码访问这个类,那么下面的属性将保持不变”之类的东西是有用的,但是我不确定是否有可能以这样一种方式扩展定义,即它只需要保持不变