Ответ 1
Это не означает ничего, особенно в отношении 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
во многих отношениях, поэтому трудно поддерживать инварианты "имеет реальное значение". - Java имеет потоки, что означает, что классы, которые не синхронизируются, имеют проблемы с сохранением инвариантов, которые полагаются на последовательные операции в потоке, происходящем вместе.
- У Java есть исключения, которые упрощают сохранение таких инвариантов, как "возвращает результат с помощью свойства p или не возвращает результат", но сложнее поддерживать такие инварианты, как "всегда возвращает результат".
† - Внешность или Нарушение правил TCB - это событие, которое оптимистически предполагает системный дизайнер, не произойдет.
Обычно мы просто верим, что основное оборудование работает так, как рекламируется, когда речь идет о свойствах высокоуровневых языков, построенных на них, и наши аргументы, которые сохраняются инвариантами, не учитывают возможность:
- Программист, использующий отладочные перехватчики для изменения локальных переменных в качестве программы, работает таким образом, что код не может.
- Ваши коллеги не используют отражение с помощью
setAccessible
для изменения таблиц поискаprivate
. - Loki меняет физику, заставляя ваш процессор неправильно сравнивать два числа.
Для некоторых систем наш TCB может включать только части системы, поэтому мы можем не предполагать, что
- Администратор или привилегированный демон не убьет наш JVM-процесс,
но мы можем предположить, что
- Мы можем поставить контрольную точку в надежную транзакционную файловую систему.
Система более высокого уровня, чем больше ее TCB, тем более ненадежные вещи, которые вы можете получить из своего TCB, тем вероятнее, что ваши инварианты будут удерживаться, и чем более надежной будет ваша система в долгосрочной перспективе работать.