Что такое инвариант класса в Java?

Я погуглил тему, но кроме Википедии я не нашел больше полезной документации или статей.

Кто-нибудь может объяснить мне в простых словах, что это значит, или отослать меня к какой-нибудь красивой и понятной документации?

3 ответа

Решение

Это не означает ничего особенного в отношении Java.

Инвариант класса - это просто свойство, которое сохраняется для всех экземпляров класса всегда, независимо от того, что делает другой код.

Например,

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

X имеет инвариант класса, что существует y собственность и никогда null и это имеет значение типа Y,

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++;
  }
}

но не в состоянии сохранить инвариант, который вызывает count всегда успешно (обычно отсутствуют нарушения TCB), потому что count может вызвать исключение или заблокировать, если заблокированный поток владеет монитором счетчика.

Каждый язык с классами позволяет легко поддерживать некоторые инварианты классов, но не другие. Java не является исключением:

  1. Классы Java постоянно имеют или не имеют свойств и методов, поэтому инварианты интерфейса просты в обслуживании.
  2. Классы Java могут защитить их private поля, так что инварианты, которые полагаются на личные данные, легко поддерживать.
  3. Классы Java могут быть конечными, поэтому можно поддерживать инварианты, которые полагаются на отсутствие кода, который нарушает инвариант путем создания вредоносного подкласса.
  4. Java позволяет null во что бы то ни стало проникнуть значениями, поэтому трудно поддерживать инварианты "имеет реальную ценность".
  5. В Java есть потоки, что означает, что у классов, которые не синхронизируются, возникают проблемы с поддержанием инвариантов, которые полагаются на последовательные операции в потоке, происходящем вместе.
  6. В Java есть исключения, которые позволяют легко поддерживать инварианты, такие как "возвращает результат со свойством p или не возвращает результата", но сложнее поддерживать инварианты, такие как "всегда возвращает результат".

† - Внешность или нарушение TCB - это событие, которое, как оптимистично полагает разработчик системы, не произойдет.

Как правило, мы просто верим, что базовое оборудование работает так, как заявлено, когда речь идет о свойствах построенных на них языков высокого уровня, и наши аргументы, которые содержат инварианты, не учитывают возможность:

  • Программист, использующий отладочные хуки для изменения локальных переменных, так как программа работает так, как не может код.
  • Ваши сверстники не используют отражение с setAccessible модифицировать private справочные таблицы.
  • Локи изменяют физику, заставляя ваш процессор неправильно сравнивать два числа.

Для некоторых систем наш TCB может включать только части системы, поэтому мы не можем предполагать, что

  • Администратор или привилегированный демон не убьет наш процесс JVM,

но мы можем предположить, что

  • Мы можем проверить надежную транзакционную файловую систему.

Чем выше система, тем больше ее TCB, как правило, но чем больше ненадежных вещей вы сможете извлечь из TCB, тем выше вероятность того, что ваши инварианты будут сохранены, и тем более надежной будет ваша система в долгосрочной перспективе.

Инвариант означает что-то, что должно соответствовать его условиям независимо от того, какие изменения или кто бы ни использовал / преобразовывает это. То есть свойство класса всегда выполняет или удовлетворяет некоторому условию даже после прохождения преобразований с использованием открытых методов. Таким образом, клиент или пользователь этого класса гарантирован о классе и его свойствах.

Например,

  1. Условие для аргумента функции заключается в том, что оно всегда должно быть> 0 (больше нуля) или не должно быть нулевым.
  2. Свойство imum_account_balance класса учетной записи указывает, что оно не может быть ниже 100. Поэтому все открытые функции должны соблюдать это условие и обеспечивать инвариант класса.
  3. основанная на правилах зависимость между переменными, то есть значение одной переменной зависит от другой, поэтому, если одно изменяется с использованием некоторого правила-фиксатора, другое также должно меняться. Эта связь между 2 переменными должна быть сохранена. Если это не так, то инвариант нарушается.

Это факты, которые должны быть правдивыми в отношении класса экземпляра. Например, если у класса есть свойство X, а инвариант может иметь значение X, оно должно быть больше 0. Насколько мне известно, нет встроенного метода для поддержки инвариантов, вы должны сделать свойства частными и убедиться, что ваши методы получения и установки устанавливают свойство инвариантности.

Доступны аннотации, которые могут проверять свойства с помощью отражения и перехватчиков. http://docs.oracle.com/javaee/7/api/javax/validation/constraints/package-summary.html

Другие вопросы по тегам