Java `final` yöntemi: ne vaat ediyor?


141

Bir Java sınıfında final, bu yöntemin geçersiz kılınmayabileceğini işaretlemek için bir yöntem olarak tanımlanabilir :

public class Thingy {
    public Thingy() { ... }
    public int operationA() {...}
    /** this method does @return That and is final. */
    public final int getThat() { ...}
}

Bu açıktır ve yanlışlıkla geçersiz kılmaya veya belki de performansa karşı korunmak için bazı yararlı olabilir - ama bu benim sorum değil.

Sorum şu: OOP açısından bakıldığında final, sınıf tasarımcısının bir yöntem tanımlayarak bu yöntemin her zaman açıklandığı veya ima edildiği gibi çalışacağını vaat ettiğini anladım . Ancak, yöntemin yaptığı şey daha karmaşıksa, sadece bir özellik sunmaktan sonra, bu genellikle sınıf yazarının etkisi dışında olabilir .

Sözdizimsel kısıtlama benim için açık, ama OOP anlamında ne anlama geliyor? Is finalEn sınıf yazarlar tarafından bu anlamda doğru kullanıldığında?

Bir finalyöntem ne tür bir “sözleşme” vaat ediyor?

Yanıtlar:


156

Belirtildiği gibi final, yöntemin geçersiz kılınamayacağını (nesne kapsamı için) veya gizlenemediğini (statik için) işaretlemek için bir Java yöntemiyle kullanılır. Bu, orijinal geliştiricinin alt sınıflar tarafından değiştirilemeyen işlevsellik oluşturmasına izin verir ve sağladığı garantidir.

Bu, yöntem genel olmayan alanlar / yöntemler gibi diğer özelleştirilebilir bileşenlere dayanıyorsa, son yöntemin işlevselliğinin yine de özelleştirilebilir olabileceği anlamına gelir. Kısmi özelleştirmeye izin verdiği için (polimorfizm ile) bu iyidir.

Bir şeyin özelleştirilebilir olmasını önlemenin birkaç nedeni vardır, bunlardan bazıları:

  • Performans - Bazı derleyiciler işlemi, özellikle yan etkileri olmayan işlemi analiz edebilir ve optimize edebilir.

  • Kapsüllenmiş veriler elde edin - niteliklerinin yapım zamanında ayarlandığı ve asla değiştirilmemesi gereken sabit Nesnelere bakın. Veya bu özelliklerden türetilen hesaplanmış bir değer. Buna iyi bir örnek Java Stringsınıfıdır.

  • Güvenilirlik ve Sonuç - Nesne ilkel (oluşur int, char, doublevs.) ve / veya diğer nesneler. Bu bileşenler için geçerli olan tüm işlemler, daha büyük Nesnede kullanıldıklarında geçerli veya mantıklı olmamalıdır. finalBunu sağlamak için değiştirici ile yöntemler kullanılabilir. Counter sınıfı iyi bir örnektir.


public class Counter {
    private int counter = 0;

    public final int count() {
        return counter++;
    }

    public final int reset() {
        return (counter = 0);
    }
}

Eğer public final int count()yöntem değildir final, böyle bir şey yapabilirsiniz:

Counter c = new Counter() {   
    public int count() {
        super.count();   
        return super.count();   
    } 
}

c.count(); // now count 2

Veya bunun gibi bir şey:

Counter c = new Counter() {
    public int count() {
        int lastCount = 0;
        for (int i = super.count(); --i >= 0; ) {
            lastCount = super.count();
        }

        return lastCount;
    }
}

c.count(); // Now double count

27

Nihai bir yöntem ne tür bir “sözleşme” vaat ediyor?

Diğer yöne bakın, herhangi bir nihai olmayan yöntem, kendi uygulamanızla geçersiz kılabileceğinizin örtülü garantisini verir ve sınıf yine de beklendiği gibi çalışır. Sınıfınızın bir yöntemin üzerine yazmayı desteklediğini garanti edemiyorsanız, bunu sonlandırmanız gerekir.


Ama bu görüş benim orijinal sorum için "bu son yöntem her zaman söz verildiği gibi davranacak" anlamına gelmiyor mu? Çünkü, eğer denersem çağıran yöntem geçersiz kılınmış olabilir ve bu nedenle son yöntemin davranışını garanti edemiyorum?
towi

8

Her şeyden önce, soyut olmayan sınıfların finalyanı sıra alanları ve yöntemleri işaretleyebilirsiniz. Bu şekilde tüm sınıf alt sınıflara ayrılamaz. Böylece, sınıfın davranışı düzeltilecektir.

finalBu yöntemler nihai olmayan yöntemler olarak adlandırılıyorsa , işaretleme yöntemlerinin davranışlarının alt sınıflarda aynı olacağını garanti etmediğini kabul ediyorum . Davranışın gerçekten düzeltilmesi gerekiyorsa, bu kural ve dikkatli tasarımla başarılmalıdır. Ve bunu javadoc'ta düşünmeyi unutmayın! (Java belgeleri)

Son olarak, en finalönemlisi, Java Bellek Modeli'nde (JMM) anahtar kelimenin çok önemli bir rolü vardır. JMM tarafından finalalanların görünürlüğünü sağlamak için doğru senkronizasyona ihtiyacınız olmadığı garanti edilir . Örneğin:

class A implements Runnable {
  final String caption = "Some caption";                           

  void run() {
    // no need to synchronize here to see proper value of final field..
    System.out.println(caption);
  }
}  

evet son sınıfları biliyorum - kolay durum. JMM ile son alanlar hakkında iyi bir nokta, senkronizasyona gerek yok ... hmm: bu sadece "işaretçi" yi gösteriyor, değil mi? Yine de atıfta bulunulan nesneyi senkronize edemedim (tamam, içinde Stringdeğil, kullanıcı tanımlı sınıflarda). Ama "final davranışı garanti etmez" hakkında söyledikleriniz tam olarak benim açımdan. Katılıyorum, doktor ve tasarım önemlidir.
towi

@towi doğru finalgibi bileşik nesnelerde yapılan değişikliklerin görünürlüğünü sağlamaz Map.
Victor Sorokin

0

"Nihai" kullanımı ve bunun yazılımın genel tasarım sözleşmesini nasıl etkilediği hakkında herhangi bir iddiada bulunabileceğinizden emin değilim. Hiçbir geliştiricinin bu yöntemi geçersiz kılamayacağı ve sözleşmesini bu şekilde geçersiz kılamayacağı garanti edilir. Ancak diğer yandan, son yöntem, değerleri alt sınıflar tarafından ayarlanır sınıf veya örnek değişkenleri bağlı olabilir, ve diğer sınıf yöntemleri çağırabilir edilir geçersiz. Bu yüzden final en çok çok zayıf bir garantidir.


1
Evet, demek istediğim bu. Sağ. Ben "zayıf garanti" terimini seviyorum :-) Ve ben (çoğunlukla) C ++ 's gibi const. Olarak char const * const = "Hello"veya char const * const addName(char const * const name) const...
towi

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.