Java'da sınıf değişmezi nedir?


94

Konuyu Google'da araştırdım, ancak Wikipedia'nın yanı sıra başka yararlı belge veya makale bulamadım.

Biri bana bunun ne anlama geldiğini basit bir şekilde açıklayabilir veya beni güzel ve anlaşılması kolay bazı belgelere yönlendirebilir mi?


2
Soru için +1 çünkü Wikipedia sayfasında yapabileceğinizi bilmediğim bir şey için gerçekten harika bir örnek var - hatta örnekleri var. Yine de açıklamaları sizin için yapabileceğimden daha iyi; oldukça basit.
iandisme


Java yazılmış değişmezlerle ilgileniyorsanız, Java sözleşmeleriyle ilgileniyor olabilirsiniz .
Mike Samuel

Yanıtlar:


93

Özellikle Java ile ilgili olarak hiçbir şey ifade etmiyor.

Bir sınıf değişmezi, başka bir kod ne yaparsa yapsın, her zaman bir sınıfın tüm örneklerini tutan bir özelliktir.

Örneğin,

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

X, bir yözellik olduğuna dair sınıf değişmezine sahiptir ve hiçbir zaman yoktur nullve bir tür değerine sahiptir Y.

class Counter {
  private int x;

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

Bu, iki önemli değişmezi korumayı başaramaz:

  1. Bu count, olası yetersizlik nedeniyle asla negatif bir değer döndürmez.
  2. Bu çağrılar countkesinlikle monoton bir şekilde artıyor.

Değiştirilmiş sınıf, bu iki değişmezi korur.

class Counter {
  private int x;

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

... ancak counther zaman normal şekilde başarılı olma çağrısı yapan değişmezi koruyamaz (TCB ihlalleri ), çünkü countbir istisna atabilir veya kilitli bir iş parçacığının sayacın monitörüne sahip olması durumunda engelleyebilir.

Sınıfları olan her dil, bazı sınıf değişmezlerini korumayı kolaylaştırırken bazılarını korumayı kolaylaştırır. Java bir istisna değildir:

  1. Java sınıfları sürekli olarak özelliklere ve yöntemlere sahiptir veya yoktur, bu nedenle arayüz değişmezlerinin bakımı kolaydır.
  2. Java sınıfları privatealanlarını koruyabilir , bu nedenle özel verilere dayanan değişmezlerin bakımı kolaydır.
  3. Java sınıfları nihai olabilir, bu nedenle kötü amaçlı bir alt sınıf oluşturarak değişmezi ihlal eden hiçbir kodun olmamasına dayanan değişmezler korunabilir.
  4. Java, nulldeğerlerin birçok şekilde gizlice girmesine izin verir , bu nedenle "gerçek bir değere sahip" değişmezlerini korumak zordur.
  5. Java'nın evreleri vardır, bu, senkronize olmayan sınıfların, birlikte gerçekleşen bir iş parçacığındaki sıralı işlemlere dayanan değişmezleri korumada sorun yaşadığı anlamına gelir.
  6. Java, "p özelliğine sahip bir sonuç döndürür veya sonuç döndürmez" gibi değişmezleri korumayı kolaylaştıran ancak "her zaman bir sonuç döndürür" gibi değişmezleri sürdürmeyi zorlaştıran istisnalara sahiptir.

† - Bir dışsallık veya TCB ihlali , bir sistem tasarımcısının iyimser bir şekilde olmayacağını varsaydığı bir olaydır.

Tipik olarak, temel donanımın, üzerlerine inşa edilen yüksek seviyeli dillerin özellikleri hakkında konuşurken reklamı yapıldığı gibi çalıştığına ve değişmezlerin sahip olduğu argümanlarımızın şu olasılıkları hesaba katmadığına güveniyoruz:

  • Bir program kodun yapamayacağı şekilde çalışırken yerel değişkenleri değiştirmek için hata ayıklama kancalarını kullanan bir programcı.
  • Akranlarınız, arama tablolarını setAccessibledeğiştirmek için yansıma kullanmaz private.
  • Loki, işlemcinizin iki sayıyı yanlış karşılaştırmasına neden olan fiziği değiştiriyor.

Bazı sistemler için TCB'miz sistemin yalnızca parçalarını içerebilir, bu nedenle şunu varsaymayabiliriz:

  • Bir yönetici veya ayrıcalıklı bir arka plan programı JVM sürecimizi öldürmez,

... ancak şunu varsayabiliriz:

  • Güvenilir bir işlem dosya sistemini kontrol edebiliriz.

Bir sistem ne kadar yüksek seviyeli olursa, TCB'si tipik olarak o kadar büyüktür, ancak TCB'nizden ne kadar güvenilmez şeyler elde ederseniz, değişmezlerinizin tutma olasılığı o kadar artar ve uzun vadede sisteminiz o kadar güvenilir olur.


2
" countAsla aynı değeri iki kez döndürmeyen" gerçekten bir sınıf değişmezi olarak kabul edilir mi?
ruakh

1
@ruakh, bu iyi bir soru. Ben tam emin değilim. HashCode kararlılığı gibi şeyler (her örnek için i, i.hashCode () değişmez) genellikle daha önce döndürülen değerler hakkında akıl yürütmeyi gerektiren sınıf değişmezleri olarak adlandırılır, bu nedenle "her i örneği için, i.count () not in (i.count () öğesinin önceki sonuçları) "bir sınıf değişmezidir.
Mike Samuel

@ruakh Bu saf bir tanım değil mi? Böyle bir değişmez varsayarsam, neden olmasın? Kesinlikle ilginç ve önemli bir garanti olabilir (örneğin benzersiz kimlikler oluşturmak için). Şahsen ben de "bu sınıfa yalnızca tek iş parçacıklı kod erişirse, aşağıdaki özellikler geçerli olur" gibi bir şeyin yararlı olduğunu düşünüyorum, ancak tanımı, yalnızca belirli olduğunda tutması gerekecek şekilde genişletmenin mümkün olup olmadığından emin değilim koşullar doğrudur. (Ve yansıma düşünüldüğünde, başka türlü ilginç bir şeyi garanti etmek temelde imkansızdır!)
Voo

1
@ruakh - bunu bir sınıf değişmezi veya bir yöntem değişmezi olarak modelleyebilirsiniz. Her iki durumda da, modelleme, belirli bir nesne üzerinde yönteme yapılan önceki çağrıların kavramsal geçmişini gerektirir. Aslında, bunu yöntemde bir son koşul olarak bile modelleyebilirsiniz; yani sonuç değerinin daha önce döndürülmemiş olması.
Stephen C

@Voo: Re: "Bu saf bir tanım şey değil mi?": Elbette, ama buradaki soru "'sınıf değişmezi' nedir?" Olduğundan, tanımın% 100 alakalı olduğunu düşünüyorum. Mümkün olduğu ölçüde, net örnekler kullanmak ya da net olmayan vakaları açıkça belirtmek tercih edilebilir görünüyor. (Bu arada, örneğe aktif olarak katılmıyorum; sadece şaşırdım ve emin olmak için soruyordum.)
ruakh

22

Değişmezlik, değişen veya onu kullanan / dönüştüren ne olursa olsun koşullarına bağlı kalması gereken bir şey anlamına gelir. Yani, bir sınıfın bir özelliği, kamusal yöntemler kullanılarak dönüşümlerden geçtikten sonra bile her zaman bazı koşulları yerine getirir veya karşılar. Böylece, bu sınıfın müşterisi veya kullanıcısı, sınıf ve mülkiyeti konusunda güvence altına alınır.

Örneğin,

  1. Bir işlev bağımsız değişkeninin koşulu, her zaman> 0 (sıfırdan büyük) olması veya boş olmaması gerektiğidir.
  2. Bir hesap sınıfı durumunun Minimum_account_balance özelliği 100'ün altına düşemez. Dolayısıyla, tüm genel işlevler bu koşula uymalı ve sınıfta değişmezliği sağlamalıdır.
  3. Değişkenler arasındaki kurala dayalı bağımlılık, yani bir değişkenin değeri diğerine bağlıdır, bu nedenle biri değişirse, bazı düzeltme kuralı kullanılarak diğeri de değişmelidir. 2 değişken arasındaki bu ilişki korunmalıdır. Aksi takdirde, değişmez ihlal edilir.

12

Bir örnek sınıfı hakkında doğru olması gereken gerçeklerdir. Örneğin, bir sınıf X özelliğine sahipse ve değişmez X, 0'dan büyük olmalıdır. Bildiğim kadarıyla, değişmezleri korumak için yerleşik bir yöntem yoktur, özellikleri özel yapmalı ve alıcılarınızın ve ayarlayıcılarınızın değişmezlik özelliğini uyguladığından emin olmalısınız.

Yansıma ve durdurucuları kullanarak özellikleri kontrol edebilen ek açıklamalar vardır. http://docs.oracle.com/javaee/7/api/javax/validation/constraints/package-summary.html

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.