Che cos'è una classe invariante in java?


93

Ho cercato su Google l'argomento, ma oltre a Wikipedia non ho trovato ulteriore documentazione o articoli utili.

Qualcuno può spiegarmi in parole semplici cosa significa o rimandarmi a una documentazione carina e di facile comprensione?


2
+1 per la domanda perché la pagina di Wikipedia ha un ottimo esempio di qualcosa che non sapevo potessi fare - ha anche degli esempi. La loro spiegazione è migliore di quanto potrei fare per te però; è abbastanza semplice.
iandisme


Se sei interessato alle invarianti rispetto a Java, forse saresti interessato ai contratti per Java .
Mike Samuel

Risposte:


91

Non significa niente in particolare in riferimento a java.

Una classe invariante è semplicemente una proprietà che vale per tutte le istanze di una classe, sempre, indipendentemente da ciò che fa l'altro codice.

Per esempio,

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

X ha la classe invariante che esiste una yproprietà e non lo è mai nulle ha un valore di tipo Y.

class Counter {
  private int x;

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

non riesce a mantenere due importanti invarianti

  1. Non countrestituisce mai un valore negativo a causa di un possibile underflow.
  2. Quelle chiamate a countstanno aumentando rigorosamente monotonicamente.

La classe modificata conserva questi due invarianti.

class Counter {
  private int x;

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

ma non riesce a preservare l'invariante che chiama per countavere sempre successo normalmente (assente TCB-violazioni ) perché countpotrebbe generare un'eccezione o potrebbe bloccarsi se un thread con deadlock possiede il monitor del contatore.

Ogni lingua con le classi rende facile mantenere alcune invarianti di classe ma non altre. Java non fa eccezione:

  1. Le classi Java hanno costantemente o non hanno proprietà e metodi, quindi le invarianti dell'interfaccia sono facili da mantenere.
  2. Le classi Java possono proteggere i loro privatecampi, quindi le invarianti che si basano su dati privati ​​sono facili da mantenere.
  3. Le classi Java possono essere finali, quindi è possibile mantenere invarianti che si basano sul fatto che non ci sia codice che violi un invariante creando una sottoclasse dannosa.
  4. Java consente ai nullvalori di entrare di nascosto in molti modi, quindi è difficile mantenere invarianti "ha un valore reale".
  5. Java ha thread, il che significa che le classi che non si sincronizzano hanno problemi a mantenere invarianti che si basano su operazioni sequenziali in un thread che avvengono insieme.
  6. Java ha eccezioni che rendono facile mantenere invarianti come "restituisce un risultato con la proprietà pe non restituisce alcun risultato" ma più difficile mantenere invarianti come "restituisce sempre un risultato".

† - Una violazione di esternalità o TCB è un evento che un progettista di sistemi presume ottimisticamente non accadrà.

In genere ci fidiamo solo del fatto che l'hardware di base funzioni come pubblicizzato quando si parla di proprietà di linguaggi di alto livello costruiti su di essi, e le nostre argomentazioni che valgono le invarianti non tengono conto della possibilità di:

  • Un programmatore che usa gli hook di debug per alterare le variabili locali mentre un programma viene eseguito in modi che il codice non può.
  • I tuoi colleghi non usano la riflessione con setAccessibleper modificare privatele tabelle di ricerca.
  • Loki altera la fisica causando il confronto errato del processore tra due numeri.

Per alcuni sistemi il nostro TCB potrebbe includere solo parti del sistema, quindi potremmo non assumerlo

  • Un amministratore o un demone privilegiato non ucciderà il nostro processo JVM,

ma potremmo presumere che

  • Possiamo controllare un file system transazionale affidabile.

Più alto è un sistema, più grande è il suo TCB in genere, ma più cose inaffidabili puoi ottenere dal tuo TCB, più è probabile che i tuoi invarianti siano mantenuti e più affidabile sarà il tuo sistema a lungo termine.


1
"Che countnon restituisce mai due volte lo stesso valore" è davvero considerato una classe invariante?
ruakh

@ruakh, questa è una buona domanda. Non sono molto sicuro. Cose come la stabilità del codice hash (per ogni istanza i, i.hashCode () non cambia) sono spesso chiamate invarianti di classe che richiedono un ragionamento sui valori restituiti in precedenza, quindi sembra ragionevole dire che "per ogni istanza i, i.count () not in (previous results of i.count ()) "è una classe invariante.
Mike Samuel

@ruakh Non è una cosa per pura definizione? Se postulo una tale invariante, perché no? Certamente può essere una garanzia interessante e importante (diciamo per la generazione di ID univoci). Personalmente penso anche che qualcosa del tipo "se solo il codice a thread singolo accede a questa classe, le seguenti proprietà manterranno" sia utile, ma non sono sicuro che sia possibile estendere la definizione in modo tale che debba essere mantenuta solo finché certi le condizioni sono vere. (E considerando la riflessione è praticamente impossibile garantire altrimenti qualcosa di interessante!)
Voo

1
@ruakh: puoi modellarlo come invariante di classe o invariante di metodo. In ogni caso, la modellazione richiede una cronologia concettuale delle precedenti chiamate al metodo su un oggetto specifico. In realtà, potresti persino modellarlo come una post-condizione sul metodo; cioè che il valore del risultato è uno che non è stato restituito in precedenza.
Stephen C

@Voo: Re: "Non è una questione di pura definizione?": Certamente, ma poiché la domanda qui è: "Cos'è un 'invariante di classe'?", Penso che la definizione sia pertinente al 100%. Sembra preferibile, per quanto possibile, utilizzare esempi chiari, oppure richiamare esplicitamente casi di non chiarezza. (A proposito, non sono attivamente in disaccordo con l'esempio; ne sono rimasto semplicemente sorpreso e
chiedevo per esserne

20

Invariante significa qualcosa che dovrebbe attenersi alle sue condizioni, indipendentemente da qualsiasi cambiamento o da chiunque lo usi / trasformi. Vale a dire, una proprietà di una classe soddisfa o soddisfa sempre alcune condizioni anche dopo aver attraversato trasformazioni utilizzando metodi pubblici. Quindi, il cliente o l'utente di questa classe è assicurato sulla classe e sulla sua proprietà.

Per esempio,

  1. condizione sull'argomento della funzione è che, dovrebbe essere sempre> 0 (maggiore di zero) o non dovrebbe essere nullo.
  2. La proprietà minimum_account_balance di una classe di account afferma, non può essere inferiore a 100. Quindi tutte le funzioni pubbliche dovrebbero rispettare questa condizione e garantire l'invariante di classe.
  3. dipendenza basata su regole tra le variabili, cioè il valore di una variabile dipende da un'altra, quindi se una cambia, usando qualche regola fissa, anche l'altra deve cambiare. Questa relazione tra 2 variabili deve essere preservata. In caso contrario, l'invariante viene violato.

11

Sono fatti che devono essere veri su una classe di istanza. Ad esempio, se una classe ha una proprietà X e invariante può essere X deve essere maggiore di 0. Per quanto ne so non esiste un metodo integrato per mantenere invarianti, devi rendere le proprietà private e assicurarti che i tuoi getter e setter applichino la proprietà di invarianza.

Sono disponibili annotazioni che possono controllare le proprietà utilizzando la riflessione e gli intercettori. http://docs.oracle.com/javaee/7/api/javax/validation/constraints/package-summary.html

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.