This does not mean anything, especially in relation to java.
A class invariant is simply a property that runs for all instances of the class, always, regardless of what the other code does.
For example,
class X { final Y y = new Y(); }
X has an invariant to the class that there is a property y , and it is never null and has a value of type y .
class Counter { private int x; public int count() { return x++; } }
unable to save two important invariants
count never returns a negative value due to a possible underflow.- What causes
count is strictly monotonically increasing.
The modified class preserves these two invariants.
class Counter { private int x; public synchronized int count() { if (x == Integer.MAX_VALUE) { throw new IllegalStateException(); } return x++; } }
but does not preserve the invariant that count causes, always succeeds normally (there are no TCB violations † ), because count can throw an exception or block if the flow monitor owns the counter monitor.
Each language with classes simplifies the preservation of some class invariants, but not others. Java is no exception:
- Java classes sequentially have or do not have properties and methods, so interface invariants are easy to maintain.
- Java classes can protect their
private fields, so invariants that rely on personal data are easy to maintain. - Java classes can be final, so you can support invariants that rely on the lack of code that violates the invariant, creating a malicious subclass.
- Java allows you to use
null values in many ways, so it’s hard to maintain the invariants “has real meaning”. - Java has threads, which means classes that are not synchronized have problems with preserving invariants that rely on consecutive operations in a thread occurring together.
- Java has exceptions that make it easier to store invariants such as "returns the result using the p property or doesn't return the result," but it's harder to maintain invariants like "always return the result."
† - Appearance or Violation of TCB rules - this is an event that is optimistically suggested by the system designer will not happen.
Usually we simply believe that the main equipment works as advertised when it comes to the properties of high-level languages built on them, and our arguments, which are kept invariant, do not take into account the possibility:
- A programmer who uses debugging hooks to change local variables as a program works in such a way that the code cannot.
- Your colleagues do not use reflection with
setAccessible to modify private lookup tables. - Loki changes physics by causing your processor to incorrectly compare two numbers.
For some systems, our TCB may include only parts of the system, so we may not assume that
- An administrator or privileged daemon will not kill our JVM process,
but we can assume that
- We can put a breakpoint in a reliable transactional file system.
A higher-level system, the larger its TCB, the more unreliable things you can get from your TCB, the more likely that your invariants will be kept, and the more reliable your system will work in the long run.