Это ничего особенного не означает применительно к 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
таблиц поиска.
- Локи изменяет физику, из-за чего ваш процессор неправильно сравнивает два числа.
Для некоторых систем наш TCB может включать только части системы, поэтому мы не можем предполагать, что
- Администратор или привилегированный демон не убьет наш процесс JVM,
... но мы можем предположить, что:
- Мы можем подключиться к надежной транзакционной файловой системе.
Чем выше уровень системы, тем больше обычно ее TCB, но чем более ненадежные вещи вы можете получить от своего TCB, тем больше вероятность того, что ваши инварианты будут соблюдаться, и тем более надежной будет ваша система в долгосрочной перспективе.
person
Mike Samuel
schedule
17.01.2012