Nihai statik yöntemin davranışı


124

Statik yöntemle değiştiricilerle oynuyordum ve garip bir davranışla karşılaştım.

Bildiğimiz gibi, örnek yerine sınıfla ilişkili oldukları için statik yöntemler geçersiz kılınamaz.

Yani aşağıdaki parçacığa sahipsem, iyi derliyor

//Snippet 1 - Compiles fine
public class A {
    static void ts() {
    }
}

class B extends A {
    static void ts() {
    }
}

Ancak, A sınıfına statik yönteme son değiştiriciyi dahil edersem, derleme başarısız olur ts () B'de A'da ts () öğesini geçersiz kılamaz; geçersiz kılınan yöntem statik nihai yöntemdir .

Statik yöntem geçersiz kılınamadığında bu neden oluyor?


2
tuhaf görünüyor, soru için +1, ama şu ana kadar cevapların hiçbiri tatmin edici değil.
Rakesh Juyal

1
Geçersiz kılınmamış. A.ts () adresinde hala orada.
Alex Feinman

Yanıtlar:


166

Statik yöntemler geçersiz kılınamaz ancak gizlenebilirler. ts()B yöntemi baskın değildir (polimorfizm için tabi olarak) ts()A ama bunu gizler. ts()B'yi çağırırsanız (NOT A.ts()veya B.ts()... sadece ts()), B'den biri aranacaktır ts(), A değil. Bu polimorfizme tabi olmadığından, A'daki çağrı asla B'deki çağrıya yönlendirilmeyecektir.

Anahtar kelime final, yöntemin gizlenmesini engeller. Bu yüzden gizlenemezler ve bunu yapma girişimi bir derleyici hatasıyla sonuçlanacaktır.

Bu yardımcı olur umarım.


30
Belki de cevabınızı bitirmek için, ki sanırım buradaki problem temelde kötü bir derleyici hata mesajıdır: B'nin A'da ts () 'yi gizleyemeyeceğini söylemesi gerekir.
Sean Owen

2
@Sean Owen: Ben de öyle düşünüyorum. 'Gizle' terimi Java Spesifikasyonunda bile kullanılmaktadır, bu yüzden neden onu derleyici mesajında ​​kullanmayalım?
NawaMan

2
Bu neden bir özelliktir? Hangi bağlamda faydalı olur?
user253751

public class Test {son statik public void main (String ... srik) {System.out.println ("Ana yöntemde"); ts (); } public static void ts () {Child c = new Child (); c.ts (); System.out.println ("Test ts"); }} public class Çocuk genişler Test {public static void ts () {System.out.println ("Child ts"); }} Merhaba, bu senaryoda neler olduğunu açıklayabilir misiniz
srikanth r

@SeanOwen Bunun da doğru olduğunu düşünmüyorum, derleyici A#tsmiras alındığından ve böyle bir yöntem zaten mevcut olduğundan B, sadece aynı imzaya sahip iki yönteme ve farklı bir değiştiriciye ( final) sahip olmanın aşırı yük olarak çalışmayacağını söylemelidir . Keşke bunun için basit bir mesaj düşünebilseydim
Eugene

13

statik yöntemler geçersiz kılınamaz

Bu tam olarak doğru değil. Örnek kod gerçekten B'deki ts yönteminin A'daki ts yöntemini gizlediği anlamına gelir. Dolayısıyla bu tam olarak geçersiz kılmaz. Üzerinde fazla Javaranch güzel bir açıklama yoktur.


4
Kesin değil, doğru. statik yöntemler geçersiz kılınamaz, ancak bunları sınıf adı yerine bir örnek başvurusunda çağırıyorsanız gizlenebilir.
John Mercier

1
Maalesef bağlantınız artık çalışmıyor. Bunu düzeltmek mümkün mü?
Mathias Bader

Javaranch bağlantısı çalışmıyor, ancak anahtar kelimeleri Google'da araştırmak bu bağlantıyı kod çiftliğinde buldu
Sundeep

Gönderiyi, Sundeep tarafından yayınlanan bağlantıyla ölü bağlantıyı değiştirerek düzenledim.
MC İmparator

10

Statik yöntemler örneğe değil sınıfa aittir.

A.ts()ve B.ts()her zaman ayrı yöntemler olacaktır.

Gerçek sorun, Java'nın bir örnek nesnede statik yöntemler çağırmanıza izin vermesidir. Üst sınıftan aynı imzaya sahip statik yöntemler, alt sınıfın bir örneğinden çağrıldığında gizlenir . Ancak, son yöntemleri geçersiz kılamaz / gizleyemezsiniz .

Hata mesajının geçersiz kılınmak yerine gizli kelimesini kullanacağını düşünürdünüz ...


6

Aşağıdakileri göz önünde bulundurarak kendinizi statik bir yöntemi son haline getirmeyi düşünecek konumda bulabilirsiniz:

Aşağıdaki sınıflara sahip olmak:

class A {
    static void ts() {
        System.out.print("A");
    }
}
class B extends A {
    static void ts() {
        System.out.print("B");
    }
}

Şimdi bu yöntemleri çağırmanın 'doğru' yolu,

A.ts();
B.ts();

sonuçlanır, ABancak yöntemleri örneklerde de çağırabilirsiniz:

A a = new A();
a.ts();
B b = new B();
b.ts();

bu da sonuçlanacaktır AB.

Şimdi şunları düşünün:

A a = new B();
a.ts();

yazdırırdı A. Aslında bir sınıf nesnesine sahip olduğunuz için bu sizi şaşırtabilir B. Ama onu bir referans türünden aradığınız için Aarayacaktır A.ts(). BAşağıdaki kodla yazdırabilirsiniz :

A a = new B();
((B)a).ts();

Her iki durumda da sahip olduğunuz nesne aslında sınıftan B. Ancak nesneyi işaret eden işaretçiye bağlı olarak, yöntemi içinden Aveya içinden çağıracaksınız B.

Şimdi, sınıfın geliştiricisi olduğunuzu Ave alt sınıflamaya izin vermek istediğinizi varsayalım. Ama gerçekten metodu istiyorsun ts(), ne zaman bir alt sınıftan çağrılsa bile, bu onun yapmasını istediğin şeyi yapıyor ve bir alt sınıf versiyonu tarafından gizlenmemesini istiyor. Sonra bunu yapabilir finalve alt sınıfta gizlenmesini önleyebilirsiniz. Ve aşağıdaki kodun, sınıfınızdan yöntemi çağıracağından emin olabilirsiniz A:

B b = new B();
b.ts();

Tamam, itiraf etmeliyim ki bu bir şekilde inşa edilmiş, ama bazı durumlarda mantıklı olabilir.

Örneklerde statik yöntemler çağırmamalısınız, ancak doğrudan sınıflarda - o zaman bu sorunu yaşamazsınız. Ayrıca örneğin IntelliJ IDEA, bir örnekte statik bir yöntem çağırırsanız ve ayrıca statik bir yöntemi sonlandırırsanız size bir uyarı gösterecektir.


0

B'deki ts () yöntemi, A'daki ts () yöntemini geçersiz kılmaz, basitçe başka bir yöntemdir. B sınıfı, statik olduğu için A'da ts () yöntemini görmez, bu nedenle ts () adında kendi yöntemini bildirebilir.

Bununla birlikte, yöntem nihai ise, derleyici A'da B'de geçersiz kılınmaması gereken bir ts () yöntemi olduğunu anlayacaktır.


Bunun, 'son'un neden birdenbire bu yöntemlerin bir arada var olamayacağı anlamına geldiğini açıkladığını sanmıyorum. Dediğiniz gibi, 'final' olmadan sorun yok. Bunun geçersiz olmadığını söylüyorsunuz, ama sonra problemin B'nin A'nın yöntemini geçersiz kılamaması olduğunu söylüyorsunuz.
Sean Owen

Elbette ki, B'nin A'da ts () yöntemini görmediğini ('gizli'), ancak son değiştiricinin başka bir yöntemi genişleten sınıflardan yöntemleri 'gizlemediğini' belirtiyorum. Ama eh, tamam.
amischiefr

0

Burada derleme hatasının oldukça yanıltıcı olduğunu düşünüyorum. "Geçersiz kılınan yöntem statik sondur" dememeliydi, bunun yerine "geçersiz kılınan yöntem nihaidir" demeliydi. Statik değiştirici burada önemsizdir.


1
Yani, B'deki statik yöntemin A'dakini geçersiz kıldığını mı düşünüyorsunuz?
Koray Tugay

@KorayTugay Derleyicinin ilk önce potansiyel olarak geçersiz kılınabilen yönteme bakıp bakmadığını (bir an için durağan görmezden gelir), başarısız olduğunda son olarak görüp görmediğini merak ediyorum . Sadece çılgınca bir tahmin
Eugene

Balus Bence StackOverflow'da sahip olduğunuz tek düşük kaliteli cevap bu. Tüm istisnai cevaplarınızı göz önünde bulundurursak, bu onlara ait değil. @BalusC
Koray Tugay

@KorayTugay: O zaman yorum yapacak kadar itibarım yoktu :) Eğer cevap verirseniz, cevabı silerim, sorun değil.
BalusC

0

Statik olmayan yöntemlerin aksine, statik bir yöntem Java'da geçersiz kılınamaz. Ancak statik ve statik olmayan veri üyeleri gibi miras alınırlar. Bu nedenle, ana sınıfta aynı ada sahip statik olmayan bir yöntem oluşturulamaz.

class Writer { 
    public static void doo(){
        System.out.println("sth");
    } 
}
class Author extends Writer{ 
    public void doo(){
        System.out.println("ok"); // error overridden method is static
    }
}

finalBelirli yöntemi vücut her yöntemi çağrısı çalıştırılması söz konusu anahtar kelime olmasını sağlar. Şimdi, alt sınıfta aynı ada sahip statik bir yöntem oluşturulur ve yönteme bir çağrı yapılırsa, alt sınıftaki yöntem çalıştırılır; bu, final, üst sınıftaki statik yöntem adından önce önekli ise bu durum böyle olmamalıdır. . Bu nedenle final anahtar sözcüğü, alt sınıfta aynı ada sahip yöntemin oluşturulmasını kısıtlar.

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.