¿Qué es una clase invariante en Java?

93

Busqué en Google el tema, pero además de Wikipedia no encontré más documentación o artículos útiles.

¿Alguien puede explicarme en palabras simples lo que significa o remitirme a alguna documentación agradable y fácil de entender?

Saurabh Kumar
fuente
2
+1 para la pregunta porque la página de Wikipedia tiene un gran ejemplo de algo que no sabía que podías hacer, incluso tiene ejemplos. Sin embargo, su explicación es mejor de lo que podría hacer por ti; es bastante sencillo.
iandisme
Si está interesado en invariantes con Java, tal vez le interesen los contratos para Java .
Mike Samuel
1
Una explicación más simple - < stackoverflow.com/questions/112064/what-is-an-invariant?rq=1 >
ip_x

Respuestas:

91

No significa nada en particular en referencia a java.

Un invariante de clase es simplemente una propiedad que se aplica a todas las instancias de una clase, siempre, sin importar lo que haga el otro código.

Por ejemplo,

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

X tiene la clase invariante de que hay una ypropiedad y nunca lo es nully tiene un valor de tipo Y.

class Counter {
  private int x;

  public int count() { return x++; }
}

no mantiene dos importantes invariantes

  1. Eso countnunca devuelve un valor negativo debido a un posible subdesbordamiento.
  2. Las llamadas a countestán aumentando estrictamente de manera monótona.

La clase modificada conserva esos dos invariantes.

class Counter {
  private int x;

  public synchronized int count() {
    if (x == Integer.MAX_VALUE) { throw new IllegalStateException(); }
    return x++;
  }
}

pero no conserva el invariante que llama a counttener éxito siempre con normalidad (ausencia de violaciones TCB ) porque countpodría generar una excepción o podría bloquear si un subproceso bloqueado posee el monitor del contador.

Cada idioma con clases facilita el mantenimiento de algunas invariantes de clase pero no de otras. Java no es una excepción:

  1. Las clases de Java tienen o no tienen propiedades y métodos consistentemente, por lo que las invariantes de interfaz son fáciles de mantener.
  2. Las clases de Java pueden proteger sus private campos, por lo que los invariantes que dependen de datos privados son fáciles de mantener.
  3. Las clases de Java pueden ser finales, por lo que se pueden mantener invariantes que se basan en que no hay código que viole una invariante al crear una subclase maliciosa.
  4. Java permite que los nullvalores se cuelen de muchas formas, por lo que es difícil mantener invariantes "tiene un valor real".
  5. Java tiene subprocesos, lo que significa que las clases que no se sincronizan tienen problemas para mantener invariantes que dependen de operaciones secuenciales en un subproceso que ocurren juntas.
  6. Java tiene excepciones que facilitan el mantenimiento de invariantes como "devuelve un resultado con la propiedad p o no devuelve ningún resultado", pero es más difícil mantener invariantes como "siempre devuelve un resultado".

† - Una externalidad o violación de TCB es un evento que un diseñador de sistemas asume con optimismo que no sucederá.

Por lo general, confiamos en que el hardware básico funciona como se anuncia cuando hablamos de las propiedades de los lenguajes de alto nivel construidos sobre ellos, y nuestros argumentos que sostienen los invariantes no tienen en cuenta la posibilidad de:

  • Un programador que utiliza enlaces de depuración para alterar las variables locales cuando un programa se ejecuta de formas que el código no puede.
  • Sus pares no usan la reflexión con setAccessiblepara modificar privatelas tablas de búsqueda.
  • Loki altera la física haciendo que su procesador compare incorrectamente dos números.

Para algunos sistemas, nuestro TCB puede incluir solo partes del sistema, por lo que es posible que no asumamos que

  • Un administrador o un demonio privilegiado no matará nuestro proceso JVM,

pero podríamos asumir que

  • Podemos controlar a un sistema de archivos transaccional confiable.

Cuanto más alto es un sistema, más grande es normalmente su TCB, pero cuanto menos fiables son las cosas que puede obtener de su TCB, es más probable que se mantengan sus invariantes y más fiable será su sistema a largo plazo.

Mike Samuel
fuente
1
¿"Eso countnunca devuelve el mismo valor dos veces" realmente se considera invariante de clase?
ruakh
@ruakh, esa es una buena pregunta. No estoy muy seguro. Cosas como la estabilidad de hashCode (para cada instancia i, i.hashCode () no cambia) a menudo se denominan invariantes de clase, lo que requiere razonar sobre los valores devueltos previamente, por lo que parece razonable decir que "para cada instancia i, i.count () not in (resultados anteriores de i.count ()) "es una clase invariante.
Mike Samuel
@ruakh ¿No es eso una pura definición? Si postulo tal invariante, ¿por qué no? Sin duda, puede ser una garantía importante e interesante (por ejemplo, para generar ID únicos). Personalmente, también creo que algo como "si solo un código de un solo subproceso accede a esta clase, se mantendrán las siguientes propiedades" es útil, pero no estoy seguro de si es posible extender la definición de tal manera que solo tenga que mantenerse mientras se las condiciones son verdaderas. (¡Y considerando la reflexión, es básicamente imposible garantizar algo interesante de lo contrario!)
Voo
1
@ruakh: puede modelarlo como invariante de clase o invariante de método. De cualquier manera, modelarlo requiere un historial conceptual de llamadas previas al método en un objeto específico. De hecho, incluso podría modelar esto como una condición posterior al método; es decir, que el valor del resultado es uno que no se ha devuelto anteriormente.
Stephen C
@Voo: Re: "¿No es una cuestión de definición pura?": Ciertamente, pero dado que la pregunta aquí es, "¿Qué es un 'invariante de clase'?", Creo que la definición es 100% relevante. Parece preferible, en la medida de lo posible, utilizar ejemplos bien definidos o, de lo contrario, señalar explícitamente casos de conducta no clara. (Por cierto, no estoy en desacuerdo activamente con el ejemplo; simplemente me sorprendió y estaba preguntando para asegurarme.)
ruakh
20

Invariante significa algo que debe ajustarse a sus condiciones sin importar los cambios o quien lo use / transforme. Es decir, una propiedad de una clase siempre cumple o satisface alguna condición incluso después de pasar por transformaciones utilizando métodos públicos. Entonces, el cliente o usuario de esta clase está asegurado sobre la clase y su propiedad.

Por ejemplo,

  1. La condición en el argumento de la función es que siempre debe ser> 0 (mayor que cero) o no debe ser nulo.
  2. La propiedad mínima_cuenta_balance de una clase de cuenta establece que no puede ir por debajo de 100. Por lo tanto, todas las funciones públicas deben respetar esta condición y garantizar que la clase sea invariante.
  3. Dependencia basada en reglas entre variables, es decir, el valor de una variable depende de otra, por lo que si una cambia, usando alguna regla fija, otra también debe cambiar. Esta relación entre 2 variables debe conservarse. Si no es así, se infringe la invariante.
aab10
fuente
11

Son hechos que deben ser ciertos sobre una clase de instancia. Por ejemplo, si una clase tiene una propiedad X y el invariante puede ser X, debe ser mayor que 0. Que yo sepa, no existe un método incorporado para mantener invariantes, debe hacer que las propiedades sean privadas y asegurarse de que sus captadores y definidores apliquen la propiedad de invariancia.

Hay anotaciones disponibles que pueden verificar las propiedades mediante reflexión e interceptores. http://docs.oracle.com/javaee/7/api/javax/validation/constraints/package-summary.html

Usman Ismail
fuente