98 votes

Qu'est-ce qu'un invariant de classe en Java ?

J'ai fait une recherche sur le sujet, mais à part Wikipedia (en anglais) Je n'ai pas trouvé d'autres documents ou articles utiles.

Quelqu'un peut-il m'expliquer en termes simples ce que cela signifie ou me renvoyer à une documentation agréable et facile à comprendre ?

2 votes

+1 pour la question, car la page Wikipedia donne un très bon exemple de quelque chose que je ne savais pas que l'on pouvait faire - il y a même des exemples. Leur explication est meilleure que ce que je pourrais faire pour vous ; c'est assez simple.

0 votes

Si vous vous intéressez aux invariants dans le cadre de Java, vous serez peut-être intéressé par le document suivant contrats pour Java .

100voto

Mike Samuel Points 54712

Il ne signifie rien de particulier en référence à Java.

Un invariant de classe est simplement une propriété qui s'applique à toutes les instances d'une classe, toujours, quoi que fasse le reste du code.

Par exemple,

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

X possède l'invariant de classe qu'il existe un y et il n'est jamais null et il a une valeur de type Y .

class Counter {
  private int x;

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

Cela ne permet pas de maintenir deux invariants importants :

  1. Cela count ne renvoie jamais une valeur négative en raison d'un éventuel dépassement de capacité.
  2. Cela appelle à count sont strictement monotones et croissants.

La classe modifiée préserve ces deux invariants.

class Counter {
  private int x;

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

...mais ne préserve pas l'invariant selon lequel les appels à count réussissent toujours normalement (en l'absence de violations des TCB) † ) car count peut lever une exception ou se bloquer si un thread bloqué possède le moniteur du compteur.

Chaque langage avec des classes facilite le maintien de certains invariants de classe, mais pas d'autres. Java ne fait pas exception :

  1. Les classes Java ont ou n'ont pas de propriétés et de méthodes, de sorte que les invariants d'interface sont faciles à maintenir.
  2. Les classes Java peuvent protéger leurs private Les invariants qui reposent sur des données privées sont donc faciles à maintenir.
  3. Les classes Java peuvent être finales, de sorte que les invariants qui reposent sur l'absence de code violant un invariant en créant une sous-classe malveillante peuvent être maintenus.
  4. Java permet null Il est donc difficile de maintenir les invariants "a une valeur réelle".
  5. Java dispose de threads, ce qui signifie que les classes qui ne se synchronisent pas ont des difficultés à maintenir les invariants qui reposent sur des opérations séquentielles dans un thread qui se déroulent ensemble.
  6. Java dispose d'exceptions, ce qui facilite le maintien d'invariants tels que "renvoie un résultat avec la propriété p ou ne renvoie aucun résultat", mais rend plus difficile le maintien d'invariants tels que "renvoie toujours un résultat".

† - An externalité o _TCB violation_ est un événement dont le concepteur du système suppose avec optimisme qu'il ne se produira pas.

Généralement, nous nous contentons de croire que le matériel de base fonctionne comme annoncé lorsque nous parlons des propriétés des langages de haut niveau construits sur ce matériel, et nos arguments selon lesquels les invariants sont valables ne tiennent pas compte de la possibilité de.. :

  • Un programmeur qui utilise des crochets de débogage pour modifier les variables locales pendant l'exécution d'un programme d'une manière que le code ne peut pas faire.
  • Vos pairs n'utilisent pas la réflexion avec setAccessible pour modifier private les tables de consultation.
  • Loki modifie les lois de la physique, ce qui fait que votre processeur compare mal deux nombres.

Pour certains systèmes, notre TCB peut n'inclure que des parties du système, de sorte que nous ne pouvons pas supposer que

  • Un administrateur ou un démon privilégié ne tuera pas notre processus JVM,

...mais on peut le supposer :

  • Nous pouvons faire un checkpoint vers un système de fichiers transactionnel fiable.

Plus un système est de haut niveau, plus sa TCB est généralement grande, mais plus vous pouvez retirer de choses non fiables de votre TCB, plus vos invariants ont de chances de tenir, et plus votre système sera fiable à long terme.

2 votes

Est-ce que "cela count ne renvoie jamais deux fois la même valeur" est-il vraiment considéré comme un invariant de classe ?

1 votes

@ruakh, c'est une bonne question. Je n'en suis pas tout à fait sûr. Des choses comme la stabilité du hashCode (pour chaque instance i, i.hashCode() ne change pas) sont souvent appelées des invariants de classe qui nécessitent un raisonnement sur les valeurs retournées précédemment, donc il semble raisonnable de dire que "pour chaque instance i, i.count() not in (previous results of i.count())" est un invariant de classe.

0 votes

@ruakh N'est-ce pas une question de définition pure ? Si je postule un tel invariant, pourquoi pas ? Cela peut certainement être une garantie intéressante et importante (par exemple pour générer des identifiants uniques). Personnellement, je pense aussi que quelque chose comme "si seul un code à un seul thread accède à cette classe, les propriétés suivantes tiendront" est utile, mais je ne suis pas sûr qu'il soit possible d'étendre la définition de manière à ce qu'elle ne tienne que si certaines conditions sont vraies (et compte tenu de la réflexion, il est fondamentalement impossible de garantir quoi que ce soit d'intéressant autrement).

23voto

aab10 Points 51

Invariant signifie que quelque chose doit rester dans ses conditions, quels que soient les changements ou les personnes qui l'utilisent ou le transforment. En d'autres termes, une propriété d'une classe remplit toujours certaines conditions, même après avoir subi des transformations en utilisant des méthodes publiques. Ainsi, le client ou l'utilisateur de cette classe est assuré de la qualité de la classe et de sa propriété.

Par exemple,

  1. La condition d'un argument de fonction est qu'il soit toujours > 0 (supérieur à zéro) ou qu'il ne soit pas nul.
  2. La propriété Minimum_account_balance d'une classe de compte indique qu'elle ne peut pas être inférieure à 100. Toutes les fonctions publiques doivent donc respecter cette condition et garantir l'invariance de la classe.
  3. Dépendance entre variables basée sur des règles, c'est-à-dire que la valeur d'une variable dépend d'une autre, de sorte que si l'une change, en utilisant une règle fixe, l'autre doit également changer. Cette relation entre deux variables doit être préservée. Si ce n'est pas le cas, l'invariant est violé.

12voto

Usman Ismail Points 3327

Il s'agit de faits qui doivent être vrais pour une classe d'instance. Par exemple, si une classe possède une propriété X et que l'invariant peut être X doit être supérieur à 0. À ma connaissance, il n'existe pas de méthode intégrée pour maintenir les invariants. Vous devez rendre les propriétés privées et vous assurer que vos getters et setters appliquent la propriété d'invariance.

Il existe des annotations qui permettent de vérifier les propriétés en utilisant la réflexion et les intercepteurs. http://docs.oracle.com/javaee/7/api/javax/validation/constraints/package-summary.html

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X