Co to jest niezmiennik klasy w Javie?

93

Przeszukałem temat, ale poza Wikipedią nie znalazłem żadnej dalszej przydatnej dokumentacji ani artykułów.

Czy ktoś może mi wyjaśnić prostymi słowami, co to znaczy lub odesłać do jakiejś ładnej i łatwej do zrozumienia dokumentacji?

Saurabh Kumar
źródło
2
+1 na pytanie, ponieważ strona Wikipedii ma naprawdę świetny przykład czegoś, o czym nie wiedziałem, że możesz zrobić - ma nawet przykłady. Ich wyjaśnienie jest jednak lepsze niż ja mógłbym dla ciebie zrobić; jest to całkiem proste.
iandisme
Jeśli interesują Cię niezmienniki w Javie, może zainteresowałyby Cię kontrakty na Javę .
Mike Samuel
1
Bardziej proste wyjaśnienie - < stackoverflow.com/questions/112064/what-is-an-invariant?rq=1 >
ip_x

Odpowiedzi:

92

Nie ma to żadnego szczególnego znaczenia w odniesieniu do języka Java.

Niezmiennik klasy to po prostu właściwość, która zachowuje się dla wszystkich instancji klasy, zawsze, bez względu na to, co robi inny kod.

Na przykład,

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

X ma niezmienną klasę, że istnieje ywłaściwość i nigdy nulljej nie ma i ma wartość typu Y.

class Counter {
  private int x;

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

nie zachowuje dwóch ważnych niezmienników

  1. To countnigdy nie zwraca wartości ujemnej z powodu możliwego niedomiaru.
  2. Te wezwania countsą ściśle monotoniczne.

Zmodyfikowana klasa zachowuje te dwa niezmienniki.

class Counter {
  private int x;

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

ale nie zachowuje niezmiennika, który wywołania countzawsze kończą się normalnym powodzeniem (brak naruszeń TCB ), ponieważ countmoże zgłosić wyjątek lub może zablokować, jeśli wątek z zakleszczeniem jest właścicielem monitora licznika.

Każdy język z klasami ułatwia utrzymanie pewnych niezmienników klas, a innych nie. Java nie jest wyjątkiem:

  1. Klasy Java konsekwentnie mają właściwości i metody lub nie mają, więc niezmienniki interfejsu są łatwe w utrzymaniu.
  2. Klasy Java mogą chronić swoje privatepola, więc niezmienniki, które opierają się na prywatnych danych, są łatwe w utrzymaniu.
  3. Klasy Java mogą być ostateczne, więc można zachować niezmienniki, które polegają na tym, że nie ma kodu naruszającego niezmiennik przez utworzenie złośliwej podklasy.
  4. Java pozwala nullwartościom przemykać się na wiele sposobów, więc trudno jest zachować niezmienniki „ma rzeczywistą wartość”.
  5. Java ma wątki, co oznacza, że ​​klasy, które nie są synchronizowane, mają problemy z utrzymaniem niezmienników, które polegają na sekwencyjnych operacjach w wątku, które są wykonywane razem.
  6. Java ma wyjątki, które ułatwiają utrzymanie niezmienników, takich jak „zwraca wynik z właściwością p lub nie zwraca żadnego wyniku”, ale trudniej jest zachować niezmienniki, takie jak „zawsze zwraca wynik”.

† - Zewnętrzne lub naruszenie TCB to zdarzenie, które projektant systemów optymistycznie zakłada, że ​​nie nastąpi.

Zwykle po prostu ufamy, że podstawowy sprzęt działa zgodnie z reklamą, gdy mówimy o właściwościach języków wysokiego poziomu zbudowanych na nich, a nasze argumenty, które utrzymują niezmienniki, nie uwzględniają możliwości:

  • Programista używający punktów zaczepienia do debugowania do zmiany lokalnych zmiennych, gdy program działa w sposób, którego kod nie może.
  • Twoi koledzy nie używają odbicia z setAccessibledo modyfikowania privatetabel przeglądowych.
  • Loki zmienia fizykę, powodując, że twój procesor nieprawidłowo porównuje dwie liczby.

W przypadku niektórych systemów nasza TCB może zawierać tylko części systemu, więc możemy tego nie zakładać

  • Administrator lub uprzywilejowany demon nie zabije naszego procesu JVM,

ale możemy to założyć

  • Możemy przejść do niezawodnego transakcyjnego systemu plików.

Im system wyższego poziomu, tym zwykle jest większy jego TCB, ale im bardziej zawodne rzeczy można uzyskać z TCB, tym większe jest prawdopodobieństwo, że niezmienniki się utrzymają i tym bardziej niezawodny będzie system w dłuższej perspektywie.

Mike Samuel
źródło
1
Czy „to countnigdy nie zwraca tej samej wartości dwa razy” naprawdę jest uważane za niezmienną klasę?
ruakh
@ruakh, to dobre pytanie. Nie jestem do końca pewien. Rzeczy takie jak stabilność hashCode (dla każdego wystąpienia i, i.hashCode () nie zmienia się) są często nazywane niezmiennikami klas, co wymaga rozumowania wartości zwróconych wcześniej, więc wydaje się rozsądne, aby powiedzieć, że „dla każdego wystąpienia i, i.count () not in (poprzednie wyniki i.count ()) ”jest niezmiennikiem klasy.
Mike Samuel
@ruakh Czy to nie jest czysta definicja? Jeśli postuluję taki niezmiennik, dlaczego nie? Z pewnością może to być interesująca i ważna gwarancja (np. Generowania unikalnych identyfikatorów). Osobiście uważam też, że przydatne jest coś w stylu „jeśli tylko kod jednowątkowy uzyskuje dostęp do tej klasy, następujące właściwości będą utrzymywać” jest przydatne, ale nie jestem pewien, czy możliwe jest rozszerzenie definicji w taki sposób, aby zachowywała się tylko wtedy, gdy jest pewna warunki są prawdziwe. (A biorąc pod uwagę refleksję, w zasadzie nie można zagwarantować niczego interesującego w innym przypadku!)
Voo
1
@ruakh - możesz go zamodelować jako niezmiennik klasy lub niezmiennik metody. Tak czy inaczej, jej modelowanie wymaga konceptualnej historii poprzednich wywołań metody na określonym obiekcie. Właściwie możesz nawet zamodelować to jako warunek końcowy metody; tzn. że wartość wyniku jest taka, która nie została zwrócona wcześniej.
Stephen C
@Voo: Re: „Czy to nie jest czysta definicja?”: Oczywiście, ale ponieważ pytanie brzmi: „Co to jest„ niezmiennik klasy ”?”, Myślę, że definicja jest w 100% odpowiednia. Wydaje się, że najlepiej jest, w miarę możliwości, posługiwać się jednoznacznymi przykładami lub też wyraźnie wskazać przypadki nieprecyzyjne. (Nawiasem mówiąc, nie zgadzam się aktywnie z tym przykładem; byłem po prostu zaskoczony i pytałem, żeby się upewnić.)
ruakh
20

Niezmienny oznacza coś, co powinno trzymać się swoich warunków bez względu na zmiany lub tego, kto go używa / przekształca. Oznacza to, że właściwość klasy zawsze spełnia lub spełnia jakiś warunek, nawet po przejściu transformacji przy użyciu metod publicznych. Tak więc klient lub użytkownik tej klasy ma pewność co do klasy i jej własności.

Na przykład,

  1. Warunek argumentu funkcji jest taki, że zawsze powinien być> 0 (większy od zera) lub nie powinien być zerowy.
  2. Właściwość minimum_account_balance klasy konta określa, że ​​nie może ona spaść poniżej 100. Zatem wszystkie funkcje publiczne powinny przestrzegać tego warunku i zapewniać niezmienność klas.
  3. zależność oparta na regułach między zmiennymi, to znaczy wartość jednej zmiennej zależy od innej, więc jeśli jedna zmieni się, używając jakiejś ustalonej reguły, inna również musi się zmienić. Należy zachować tę zależność między 2 zmiennymi. Jeśli tak nie jest, naruszany jest niezmiennik.
aab10
źródło
11

Są to fakty dotyczące klasy instancji, które muszą być prawdziwe. Na przykład, jeśli klasa ma właściwość X, a niezmiennik może mieć wartość X, musi być większa niż 0. O ile wiem, nie ma wbudowanej metody utrzymywania niezmienników, musisz ustawić właściwości jako prywatne i upewnić się, że metody pobierające i ustawiające wymuszają właściwość niezmienności.

Dostępne są adnotacje, które mogą sprawdzać właściwości za pomocą odbicia i przechwytywaczy. http://docs.oracle.com/javaee/7/api/javax/validation/constraints/package-summary.html

Usman Ismail
źródło