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


93

J'ai recherché le sujet sur Google, mais à part Wikipédia, je n'ai pas trouvé de documentation ou d'articles utiles.

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


2
+1 pour la question parce que la page Wikipédia a un très bon exemple de quelque chose que je ne savais pas que vous pouviez faire - elle a même des exemples. Leur explication est meilleure que je ne pourrais le faire pour vous; c'est assez simple.
iandisme


Si vous êtes intéressé par les invariants pour Java, vous seriez peut-être intéressé par les contrats pour Java .
Mike Samuel

Réponses:


91

Cela ne veut rien dire en 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, peu importe ce que fait un autre code.

Par exemple,

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

X a l'invariant de classe qu'il y a une ypropriété et ce n'est jamais nullet il a une valeur de type Y.

class Counter {
  private int x;

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

ne parvient pas à maintenir deux invariants importants

  1. Cela countne renvoie jamais une valeur négative en raison d'un éventuel dépassement inférieur.
  2. Ces appels countsont en augmentation strictement monotone.

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 parvient pas à conserver l'invariant qui appelle à counttoujours réussir normalement (absence de violations TCB ) car il countpeut lever une exception ou bloquer si un thread bloqué possède le moniteur du compteur.

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

  1. Les classes Java ont systématiquement ou n'ont pas de propriétés et de méthodes, les invariants d'interface sont donc faciles à gérer.
  2. Les classes Java peuvent protéger leurs privatechamps, les invariants qui reposent sur des données privées sont donc faciles à gérer.
  3. Les classes Java peuvent être finales, donc les invariants qui reposent sur l'absence de code qui viole un invariant en créant une sous-classe malveillante peuvent être conservés.
  4. Java permet aux nullvaleurs de se faufiler de plusieurs façons, il est donc difficile de maintenir des invariants «a une valeur réelle».
  5. Java a des threads, ce qui signifie que les classes qui ne se synchronisent pas ont du mal à maintenir les invariants qui reposent sur des opérations séquentielles dans un thread se produisant ensemble.
  6. Java a des exceptions qui facilitent la gestion des invariants tels que «renvoie un résultat avec la propriété p ou ne retourne aucun résultat», mais il est plus difficile de maintenir des invariants tels que «renvoie toujours un résultat».

† - Une externalité ou une violation TCB est un événement dont un concepteur de systèmes suppose avec optimisme qu'il ne se produira pas.

En règle générale, nous sommes convaincus que le matériel de base fonctionne comme annoncé lorsque nous parlons des propriétés des langages de haut niveau construits sur eux, et nos arguments que les invariants tiennent ne prennent pas en compte la possibilité de:

  • Un programmeur utilisant des hooks de débogage pour modifier les variables locales pendant qu'un programme s'exécute d'une manière que le code ne peut pas.
  • Vos pairs n'utilisent pas la réflexion avec setAccessiblepour modifier privateles tables de recherche.
  • Loki modifie la physique, ce qui fait que votre processeur compare incorrectement deux nombres.

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

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

mais nous pourrions supposer que

  • Nous pouvons vérifier un système de fichiers transactionnel fiable.

Plus un système est de niveau supérieur, plus son TCB est généralement grand, mais plus les choses que vous pouvez retirer de votre TCB sont peu fiables, plus vos invariants sont susceptibles de tenir et plus votre système sera fiable à long terme.


1
Est-ce que "qui countne renvoie jamais deux fois la même valeur" est vraiment considéré comme un invariant de classe?
ruakh

@ruakh, c'est une bonne question. Je ne suis pas sûr. Des choses comme la stabilité du hashCode (pour chaque instance i, i.hashCode () ne change pas) sont souvent appelées invariants de classe, ce qui nécessite un raisonnement sur les valeurs renvoyées précédemment, il semble donc raisonnable de dire que "pour chaque instance i, i.count () not in (résultats précédents de i.count ()) "est un invariant de classe.
Mike Samuel

@ruakh N'est-ce pas une pure définition? 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 un seul code 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 telle sorte qu'elle ne doive tenir que pendant les conditions sont vraies. (Et compte tenu de la réflexion, il est fondamentalement impossible de garantir quoi que ce soit d'intéressant autrement!)
Voo

1
@ruakh - vous pouvez le modéliser comme un invariant de classe ou un invariant de méthode. Dans tous les cas, sa modélisation nécessite un historique conceptuel des appels précédents à la méthode sur un objet spécifique. En fait, vous pouvez même modéliser cela comme une post-condition de la méthode; c'est-à-dire que la valeur du résultat est celle qui n'a pas été renvoyée précédemment.
Stephen C

@Voo: Re: "N'est-ce pas une pure définition?": Certainement, mais puisque la question ici est: "Qu'est-ce qu'un 'invariant de classe'?", Je pense que la définition est pertinente à 100%. Il semble préférable, dans la mesure du possible, d'utiliser des exemples clairs, ou bien de signaler explicitement les cas de non-clarté. (Au fait, je ne suis pas activement en désaccord avec l'exemple; j'en étais juste surpris et je demandais pour
m'en

20

Invariant signifie quelque chose qui devrait respecter ses conditions, quels que soient les changements ou quiconque l'utilise / le transforme. C'est-à-dire qu'une propriété d'une classe remplit ou satisfait toujours une condition même après avoir subi des transformations à l'aide de méthodes publiques. Ainsi, le client ou l'utilisateur de cette classe est assuré de la classe et de sa propriété.

Par exemple,

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

11

Ce sont des faits qui doivent être vrais sur une classe d'instances. Par exemple, si une classe a une propriété X et que l'invariant peut être X doit être supérieur à 0. À ma connaissance, il n'y a 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 disponibles qui peuvent vérifier les propriétés à l'aide de la réflexion et des intercepteurs. http://docs.oracle.com/javaee/7/api/javax/validation/constraints/package-summary.html

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.