Değişmez sınıf mı?


Yanıtlar:


136

Değişmez nesne nedir?

Değişmez bir nesne, somutlaştırıldıktan sonra durumunu değiştirmeyecek bir nesnedir.

Bir nesne nasıl değişmez hale getirilir?

Genel olarak, değişmez bir nesne, hiçbir üyesine maruz kalmayan ve ayarlayıcıları olmayan bir sınıf tanımlanarak yapılabilir.

Aşağıdaki sınıf, değişmez bir nesne oluşturacaktır:

class ImmutableInt {
  private final int value;

  public ImmutableInt(int i) {
    value = i;
  }

  public int getValue() {
    return value;
  }
}

Yukarıdaki örnekte görülebileceği gibi, değeri ImmutableIntyalnızca nesne somutlaştırıldığında ayarlanabilir ve yalnızca bir alıcıya ( getValue) sahip olarak nesnenin durumu somutlaştırmadan sonra değiştirilemez.

Bununla birlikte, nesne tarafından atıfta bulunulan tüm nesnelerin de değişmez olması gerektiğine veya nesnenin durumunu değiştirmenin mümkün olabileceğine dikkat edilmelidir.

Örneğin, bir diziye bir başvuruya veya ArrayListbir alıcı aracılığıyla elde edilmesine izin vermek, diziyi veya koleksiyonu değiştirerek dahili durumun değişmesine izin verir:

class NotQuiteImmutableList<T> {
  private final List<T> list;

  public NotQuiteImmutableList(List<T> list) {
    // creates a new ArrayList and keeps a reference to it.
    this.list = new ArrayList(list); 
  }

  public List<T> getList() {
    return list;
  }
}

Yukarıdaki kodla ilgili sorun , nesnenin kendisinin durumunun değiştirilmesine, dolayısıyla değişmez olmamasına yol açacak ArrayListşekilde elde edilebilmesi getListve manipüle edilebilmesidir.

// notQuiteImmutableList contains "a", "b", "c"
List<String> notQuiteImmutableList= new NotQuiteImmutableList(Arrays.asList("a", "b", "c"));

// now the list contains "a", "b", "c", "d" -- this list is mutable.
notQuiteImmutableList.getList().add("d");

Bu sorunu aşmanın bir yolu, alıcıdan çağrıldığında bir dizinin veya koleksiyonun bir kopyasını döndürmektir:

public List<T> getList() {
  // return a copy of the list so the internal state cannot be altered
  return new ArrayList(list);
}

Değişmezliğin avantajı nedir?

Değişmezliğin avantajı eşzamanlılık ile birlikte gelir. Değişken nesnelerde doğruluğu korumak zordur, çünkü birden fazla iş parçacığı aynı nesnenin durumunu değiştirmeye çalışıyor olabilir, bu da bazı iş parçacığının aynı nesnenin farklı bir durumunu görmesine neden olabilir, söz konusu nesneye okuma ve yazma zamanlamasına bağlı olarak nesne.

Değişmez bir nesneye sahip olunarak, nesneye bakan tüm iş parçacıkları, değişmez bir nesnenin durumu değişmeyeceğinden, aynı durumu görmesini sağlayabilir.


5
İş parçacığı güvenliği (eşzamanlılık için önemlidir) değişmezliğin tek avantajı değildir; aynı zamanda nesnelerin savunma kopyalarını oluşturmanıza gerek olmadığı anlamına gelir ve hataları önler çünkü değiştirilmemesi gereken nesneleri yanlışlıkla değiştiremezsiniz.
Jesper

7
Listenin bir kopyasını döndürmek yerine, listede return Collections.unmodifiableList(list);salt okunur bir görünüm de döndürebilirsiniz.
Jesper

19
Sınıfın da yapılması gerekiyor final. Aksi takdirde, bir ayarlayıcı yöntemle (veya diğer tür değiştirme yöntemleri ve değiştirilebilir alanlar) genişletilebilir.
Abhinav Sarkar

6
@AbhinavSarkar finalSınıfın yalnızca privatealanlara sahip olması gerekmez , çünkü alt sınıflardan erişilemezler.
icza

3
@icza sınıf kamu alıcı yöntemine sahip, çünkü biz sınıfını genişletmek ve alıcı yöntemini geçersiz ve sonra alanını değiştirebilir, nihai olmak zorunda bizim o değişmez artık değil way..so
sunil

19

Halihazırda verilen cevaplara ek olarak, gözden kaçırılması kolay bazı ayrıntılar (örn. Savunma kopyaları) olduğundan, Etkili Java, 2. Baskı'da değişmezlik hakkında okumanızı tavsiye ederim. Artı, Etkili Java 2. Baskı. her Java geliştiricisi için mutlaka okunması gereken bir kitaptır.


3
Bakılması gereken tam kaynak budur. Bahsedilen faydalar, hataya daha az eğilimli koddan iş parçacığı güvenliğine kadar uzanmaktadır.
gpampara

6

Bir sınıfı böyle değişmez kılarsınız:

public final class Immutable
{
    private final String name;

    public Immutable(String name) 
    {
        this.name = name;
    }

    public String getName() { return this.name; } 

    // No setter;
}

Bir Java sınıfını değiştirilemez kılmak için gerekenler şunlardır:

  • Sınıf şu şekilde bildirilmelidir final(Böylece alt sınıflar oluşturulamaz)
  • Sınıftaki üyelerfinal (Nesne oluşturduktan sonra değerini değiştirememek için) olarak bildirilmelidir.
  • Üyeler değerlerini almak için içindeki tüm değişkenler için Getter yöntemleri yazın
  • Setters yöntemi yok

Değişmez sınıflar kullanışlıdır çünkü
- İş parçacığı açısından güvenlidirler.
- Ayrıca tasarımınız hakkında derinlemesine bir şey ifade ediyorlar: "Bunu değiştiremezsiniz.", Uygulandığı zaman, tam da ihtiyacınız olan şeydir.


5

Değişmezlik esas olarak iki şekilde elde edilebilir:

  • finalyeniden atamayı önlemek için örnek özniteliklerini kullanma
  • Sınıfınızın içindekileri değiştirebilen herhangi bir işleme izin vermeyen bir sınıf arabirimi kullanarak (yalnızca alıcılar ve ayarlayıcı yok)

Değişmezliğin avantajları, bu nesneler üzerinde yapabileceğiniz varsayımlardır:

  • yan etkisiz kuralı kazanırsınız (bu, işlevsel programlama dillerinde gerçekten popülerdir) ve eşzamanlı bir ortamda nesneleri daha kolay kullanmanıza izin verir, çünkü bunlar atomik veya atomik olmayan bir şekilde değiştirilemeyeceklerini bilirsiniz. birçok iş parçacığı tarafından kullanılıyor
  • Dil uygulamaları, bu nesneleri farklı bir şekilde ele alabilir, onları statik veriler için kullanılan bellek bölgelerine yerleştirebilir ve bu nesnelerin daha hızlı ve daha güvenli bir şekilde kullanılmasını sağlar (bu, dizeler için JVM'nin içinde olan şeydir)

Değişmez, eşit yan etkisiz ile aynı şey değildir. Örneğin, değişmez bir nesne, bir dosyaya giriş yapmak gibi yan etkilere neden olabilir. Bir nesneyi değişmez hale getirmenin aynı zamanda onu yan etkisiz hale getirdiğini söylemek biraz yanlıştır.
Grundlefleck

1
@Grundleflek, bence bu saçları bölüyor olabilir. Sınıf, sözleşmesinin bir parçası olarak bir günlük dosyasını değiştirirse ve bu günlük dosyasına diğer sınıflar tarafından erişilebilirse, değişmez değildir. Günlük dosyası diğer sınıflardan gizlenmişse ve sınıf sözleşmesinin bir parçası değilse, sınıf etkili bir şekilde değişmezdir ve gerçekten tüm amaç ve amaçlar için yan etkisizdir. Wikipedia yan etki sayfasındaki (kaynaksız) girişte "... bir ifadenin, bir değer üretmenin yanı sıra, bazı durumu değiştirmesi veya arama işlevleriyle gözlemlenebilir bir etkileşimi varsa, bir yan etkiye sahip olduğu söylenir."
Jeff Axelrod

3

Immutable sınıflar, somutlaştırıldıktan sonra değerleri yeniden atayamaz. Yapıcı, özel değişkenlerine değerler atar. Nesne boş olana kadar, ayarlayıcı yöntemlerin kullanılamaması nedeniyle değerler değiştirilemez.

değişmez olmak için aşağıdakileri tatmin etmelidir,

  • Tüm değişkenler özel olmalıdır .
  • Mutatör yok yöntemleri (belirleyiciler) sağlanmaktadır.
  • Sınıfı nihai (Güçlü Değişmezlik) veya yöntemleri son (Hafta değişmezliği) yaparak yöntemi geçersiz kılmaktan kaçının.
  • İlkel olmayan veya değiştirilebilir sınıflar içeriyorsa derinlemesine klonlayın.

/**
* Strong immutability - by making class final
*/
public final class TestImmutablity {

// make the variables private
private String Name;

//assign value when the object created
public TestImmutablity(String name) {
this.Name = name;
}

//provide getters to access values
public String getName() {

return this.Name;
}
}

Advanteges: Değişmez nesneler, ölene kadar başlatılmış değerlerini içerir.

java-immutable-sınıfları-kısa-not


2

Değişmez sınıf , nesneleri oluşturulduktan sonra değiştirilemeyen .

Değişmez sınıflar için yararlıdır

  • Önbelleğe alma amacı
  • Eşzamanlı ortam (ThreadSafe)
  • Miras için zor
  • Değer hiçbir ortamda değiştirilemez

Misal

String Sınıfı

Kod Örneği

public final class Student {
    private final String name;
    private final String rollNumber;

    public Student(String name, String rollNumber) {
        this.name = name;
        this.rollNumber = rollNumber;
    }

    public String getName() {
        return this.name;
    }

    public String getRollNumber() {
        return this.rollNumber;
    }
}

2

Bir Java sınıfı nasıl değişmez hale getirilebilir?

JEP 359'a sahip JDK 14+ 'den " records" kullanabiliriz . Immutable sınıfı yaratmanın en basit ve acelesiz yoludur.

Bir kayıt sınıfı, kayıt için bir açıklama sağlayan ve kayıt olarak bilinen sabit bir alan kümesi için yüzeysel olarak değişmez , şeffaf bir taşıyıcıdır . Her bir yol açmaktadır sağlanan değeri ve bir tutan alanıncomponentsstatecomponentfinalaccessor ve değeri almak için yöntemi ortaya çıkarır. Alan adı ve erişimci adı, bileşenin adıyla eşleşir.

Değişmez bir dikdörtgen oluşturma örneğini düşünelim

record Rectangle(double length, double width) {}

Herhangi bir kurucu bildirmeye gerek yok, equals & hashCode yöntemlerini uygulamaya gerek yok. Sadece herhangi bir Kayıt bir ada ve bir durum açıklamasına ihtiyaç duyar.

var rectangle = new Rectangle(7.1, 8.9);
System.out.print(rectangle.length()); // prints 7.1

Nesne oluşturma sırasında değeri doğrulamak isterseniz, yapıcıyı açıkça bildirmemiz gerekir.

public Rectangle {

    if (length <= 0.0) {
      throw new IllegalArgumentException();
    }
  }

Kaydın gövdesi, statik yöntemleri, statik alanları, statik başlatıcıları, oluşturucuları, örnek yöntemlerini ve iç içe geçmiş türleri bildirebilir.

Örnek Yöntemleri

record Rectangle(double length, double width) {

  public double area() {
    return this.length * this.width;
  }
}

statik alanlar, yöntemler

Durum bileşenlerin bir parçası olması gerektiğinden, kayıtlara örnek alanları ekleyemiyoruz. Ancak statik alanlar ve yöntemler ekleyebiliriz:

record Rectangle(double length, double width) {

  static double aStaticField;

  static void aStaticMethod() {
    System.out.println("Hello Static");
  }
}

değişmezliğe ihtiyaç nedir ve bunu kullanmanın herhangi bir avantajı var mı?

Önceden gönderilen yanıtlar, değişmezlik ihtiyacını haklı çıkarmak için yeterince iyidir ve artıları


0

Değişmez nesne yapmanın başka bir yolu da Immutables.org kitaplığını kullanmaktır :

Gerekli bağımlılıkların eklendiğini varsayarak, soyut erişimci yöntemleriyle soyut bir sınıf oluşturun. Arayüzlerle ve hatta ek açıklamalarla (@ arayüz) açıklama ekleyerek aynısını yapabilirsiniz:

package info.sample;

import java.util.List;
import java.util.Set;
import org.immutables.value.Value;

@Value.Immutable
public abstract class FoobarValue {
  public abstract int foo();
  public abstract String bar();
  public abstract List<Integer> buz();
  public abstract Set<Long> crux();
}

Artık oluşturulan değişmez uygulamayı oluşturmak ve sonra kullanmak mümkündür:

package info.sample;

import java.util.List;

public class FoobarValueMain {
  public static void main(String... args) {
    FoobarValue value = ImmutableFoobarValue.builder()
        .foo(2)
        .bar("Bar")
        .addBuz(1, 3, 4)
        .build(); // FoobarValue{foo=2, bar=Bar, buz=[1, 3, 4], crux={}}

    int foo = value.foo(); // 2

    List<Integer> buz = value.buz(); // ImmutableList.of(1, 3, 4)
  }
}

0

Değişmez bir sınıf, örnekleri değiştirilemeyen bir sınıftır.

Her durumda bulunan tüm bilgiler, nesnenin ömrü boyunca sabittir, bu nedenle hiçbir değişiklik gözlenemez.

Değişmez sınıfların tasarlanması, uygulanması ve kullanılması değiştirilebilir sınıflardan daha kolaydır.

Bir sınıfı değişmez kılmak için şu beş kurala uyun:

  1. Nesnenin durumunu değiştiren yöntemler sağlamayın

  2. Sınıfın uzatılamayacağından emin olun.

  3. Tüm alanları son hale getirin.

  4. Tüm alanları özel yapın.

  5. Değiştirilebilir bileşenlere özel erişim sağlayın.

Değişmez nesneler, doğaları gereği iş parçacığı açısından güvenlidir; senkronizasyon gerektirmezler.

Değişmez nesneler özgürce paylaşılabilir.

Değişmez nesneler, diğer nesneler için harika yapı taşları oluşturur


0

@Jack, Sınıfta son alanlara ve ayarlayıcılara sahip olmak sınıfı değişmez yapmaz. final anahtar sözcüğü yalnızca bir değişkenin asla yeniden atanmadığından emin olun. Alıcı yöntemlerinde tüm alanların derin kopyasını döndürmeniz gerekir. Bu, alıcı yönteminden bir nesne aldıktan sonra nesnenin iç durumunun bozulmamasını sağlayacaktır.


-1

Anadili İngilizce olmayan bir konuşmacı olarak, "değişmez sınıf" ın "inşa edilmiş sınıf nesneleri değişmezdir" olmasının ortak yorumundan hoşlanmıyorum; daha ziyade, bunu "sınıf nesnesinin kendisi değişmez" olarak yorumlamaya meyilliyim.

Bununla birlikte, "değişmez sınıf" bir tür değişmez nesnedir. Aradaki fark, faydanın ne olduğunu yanıtlamaktır. Bildiğim kadarıyla immutable sınıfı, nesnelerinin çalışma zamanı davranış değişikliklerini engeller.


-1

Buradaki cevapların çoğu iyidir ve bazıları kurallardan bahsetmiştir ancak bu kurallara neden ve ne zaman uymamız gerektiğini kelimelere dökmenin iyi olduğunu hissediyorum. Öyleyse aşağıdaki açıklamayı veriyorum

  • Üye değişkenleri 'son' olarak bildirin - Onları nihai olarak ilan ettiğimizde, derleyici bizi onları başlatmaya zorlar. Varsayılan kurucu olarak, arg yapıcı ile doğrudan başlatabiliriz. (Aşağıdaki örnek koda bakın) ve başlatmadan sonra bunları son halleriyle değiştiremeyiz.
  • Ve elbette bu son değişkenler için Setters'ı kullanmaya çalışırsak, derleyici hata verir.

    public class ImmutableClassExplored {
    
        public final int a; 
        public final int b;
    
        /* OR  
        Generally we declare all properties as private, but declaring them as public 
        will not cause any issues in our scenario if we make them final     
        public final int a = 109;
        public final int b = 189;
    
         */
        ImmutableClassExplored(){
            this. a = 111;
            this.b = 222;
        }
    
        ImmutableClassExplored(int a, int b){
            this.a = a;
            this.b= b;
        }
    }
    

Sınıfı 'final' olarak ilan etmemiz gerekiyor mu?

  • Sınıf bildiriminde son anahtar kelime olmadan, sınıf miras alınabilir. Böylece alt sınıf, alıcı yöntemlerini geçersiz kılabilir. Burada iki senaryoyu göz önünde bulundurmalıyız:

1. Yalnızca ilkel üyelere sahip olmak: Sorunumuz yok Sınıfın yalnızca ilkel üyeleri varsa, sınıfı nihai olarak ilan etmemize gerek yoktur.

2. Nesnelerin üye değişkenler olarak kullanılması: Üye değişkenler olarak nesnelerimiz varsa, bu nesnelerin üyelerini de nihai hale getirmeliyiz. Ağacın derinliklerine inmemiz ve tüm nesneleri / ilkelleri nihai hale getirmemiz gerektiği anlamına gelir ki bu her zaman mümkün olmayabilir. Dolayısıyla geçici çözüm, kalıtımı önleyen sınıfı nihai hale getirmektir. Dolayısıyla, alıcı yöntemlerini geçersiz kılan bir alt sınıf söz konusu değildir.


-1

Lombok'un @Value ek açıklaması, değişmez sınıflar oluşturmak için kullanılabilir. Aşağıdaki kod kadar basit.

@Value
public class LombokImmutable {
    int id;
    String name;
}

Lombok'un sitesindeki belgelere göre:

@Value, @Data'nın değişmez varyantıdır; varsayılan olarak tüm alanlar özel ve nihai yapılır ve ayarlayıcılar oluşturulmaz. Sınıfın kendisi de varsayılan olarak nihai hale getirilir, çünkü değişmezlik bir alt sınıfa zorlanabilecek bir şey değildir. @Data gibi, yararlı toString (), equals () ve hashCode () yöntemleri de oluşturulur, her alan bir alıcı yöntemi alır ve her argümanı kapsayan bir kurucu (alan bildiriminde başlatılan son alanlar hariç) de oluşturulur .

Tam olarak çalışan bir örnek burada bulunabilir .


Kabul edilen bir cevaba sahip eski bir soruyu cevaplamadan önce (yeşili arayın ✓) ve diğer cevapların yanı sıra cevabınızın yeni bir şey eklediğinden veya bunlarla ilgili başka bir şekilde yardımcı olduğundan emin olun. Lütfen OP'nin sorusunu yanıtlarken dikkatli olun Bir Java sınıfı nasıl değişmez hale getirilebilir, değişmezliğe ihtiyaç nedir ve bunu kullanmanın herhangi bir avantajı var mı? . - Yalnızca kısmi bir cevap veriyorsunuz, bu da bir üçüncü taraf çerçeve / kitaplık olan Lombok'u kullanabileceğinizi belirtir, bu ille de OP'nin sorusu bununla ilgili değildir. Ayrıca Java 15 çıktı, Java recordkullanılabilirken neden Lombok kullanılsın?
Ivo Mori

Bunu nasıl başaracağıma dair seçeneklerden birini veriyorum. Herkes Java 15 kullanmıyor, bugün uygulamaların çoğu önceki sürümlerde çalışıyor, bu yüzden Lombok kullanımının neden pek mantıklı olmadığını söylüyorsunuz. Mevcut projemde yakın zamanda Java 11'e geçtik ve değişmez sınıflar elde etmek için Lombok kullanıyoruz. Ayrıca cevabım, mevcut cevapların bir ekidir. Değişmez olan zaten yanıtlandı, sanırım bunu tamamlanması için yeniden yazmamı bekliyorsunuz.
Anubhav

Yeterince adil. Ben ne aşağı ne de yukarı oy verdim. Diğer iki kişinin bu cevaba neden olumsuz oy verdiklerini göstermeye çalıştım. Cevabınızı nasıl düzenlemek isteyip istemediğiniz size kalmış.
Ivo Mori
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.