Java'da statik yöntemler neden soyut olamaz?


593

Soru Java'da, neden soyut bir statik yöntem tanımlayamıyorum? Örneğin

abstract class foo {
    abstract void bar( ); // <-- this is ok
    abstract static void bar2(); //<-- this isn't why?
}

9
Birkaç neden: statik yöntemin soyut sınıfın bir parçası olsalar bile bir gövdesi olmalıdır, çünkü statik yönteme erişmek için bir sınıf örneği oluşturmaya gerek yoktur. Bunu düşünmenin başka bir yolu, bir anlığına izin verildiğini varsayarsak, sorun statik yöntem çağrılarının herhangi bir Çalışma Süresi Türü Bilgisi (RTTI) sağlamamasıdır, örnek oluşturmaya gerek olmadığını hatırlayın, böylece yönlendirilemezler özel geçersiz kılma uygulamalarına ve böylece soyut statiklere izin vermenin hiçbir anlamı yoktur. Başka bir deyişle, bu nedenle izin verilmeyen herhangi bir polimorfizm yararı sağlayamadı.
sactiw

6
Soruyu cevaplayacak bir şeyiniz varsa , bir yorum olarak değil, bir cevap olarak gönderin
Solomon Ucko

Yanıtlar:


568

Çünkü "soyut" şu anlama gelir: "Hiçbir işlevsellik uygulamaz" ve "statik" şu anlama gelir: "Bir nesne örneğiniz olmasa bile işlevsellik vardır". Ve bu mantıklı bir çelişki.


353
Daha özlü bir cevap 'kötü dil tasarımı' olacaktır. Statik 'sınıfa ait' anlamına gelmelidir, çünkü bu sorunun gösterdiği gibi sezgisel olarak kullanılır. Python'da "sınıf yöntemi" konusuna bakın.
Alexander Ljungberg

12
@ Tomalak Özür dilerim, net değildim. Elbette statik bir yöntem 'sınıfa aittir'. Yine de, sadece aynı ad alanında yaşadığı anlamına gelir. Statik bir yöntem, sınıf nesnesinin kendisinin bir yöntemi değildir: sınıf nesnesi olarak 'this' ile çalışmaz ve kalıtım zincirine düzgün bir şekilde katılmaz. Gerçekten bir sınıf yöntemi abstract staticolsaydı mükemmel bir mantıklı olurdu. Alt sınıf nesnelerinin uygulaması gereken sınıf nesnesinin kendisinin bir yöntemi olurdu. Tabii ki, dili kavramaya rağmen işlerin cevabınızı temsil etme şekli doğru.
Alexander Ljungberg

695
Bu mantıklı bir çelişki değil, bir dil yetersizliği, diğer birçok dil bu kavramı destekliyor. "soyut" alt sınıflarda uygulanan "ortalama", "statik", "sınıf örnekleri yerine sınıf üzerinde yürütülen" anlamına gelir "Mantıksal bir çelişki yoktur.
Eric Grange

10
@Eric: Ve yine , sen için geçerli değildir söylediklerini abstract static: "alt sınıfta uygulanan" A fonksiyon X olamaz aynı anda "sınıfına infaz" edilecek - Yalnızca alt sınıf . O zaman artık soyut değil.
Tomalak

72
@ Tomakak: Mantıklarınız dairesel. static"boş değil" anlamına gelmez - bu sadece Java'nın statik yöntemlerin soyut olmasına izin vermemesinin bir sonucudur. "Sınıfta çağrılabilir" anlamına gelir. (Bu " sadece sınıfta çağrılabilir" anlamına gelmelidir , ancak bu başka bir konudur.) Java tarafından desteklenen abstract staticyöntemler, yöntem 1) alt sınıflar tarafından uygulanmalı ve 2) alt sınıfın bir sınıf yöntemidir anlamına gelmesini beklerdim. Bazı yöntemler örnek yöntemler olarak anlamsızdır. Ne yazık ki Java, soyut bir temel sınıf (veya arabirim) oluştururken bunu belirtmenize izin vermez.
Michael Carman

326

Kötü dil tasarımı. Doğrudan statik soyut yöntemi çağırmak, yalnızca bu soyut yöntemi kullanmak için bir örnek oluşturmaktan çok daha etkili olacaktır. Özellikle, soyut bir sınıfı, numaralandırmanın uzamaması için bir geçici çözüm olarak kullanırken, bu da başka bir kötü tasarım örneğidir. Umarım bu sınırlamaları bir sonraki sürümde çözerler.


25
Java tuhaf sınırlamalarla doludur. Yalnızca son değişkenlere erişen kapaklar başka bir şeydir. Ve geri kalan liste neredeyse sonsuz. Onları ve geçici çözümlerini bilmek bir Java programcısının görevidir. Eğlenmek için boş zamanlarımızda Java'dan daha iyi bir şey kullanmalıyız. Ama rahatsız etmem. İlerleme elde etmek için tohum budur.
ceving

22
"Kötü dil tasarımı" olarak adlandırdığınız şeyin gerçekten daha çok "Koruyucu dil tasarımı" olduğuna inanıyorum. Bunun amacı, programcıların gereksiz dil özellikleri nedeniyle yaptığı OO ilkesi ihlallerini sınırlamaktır.
etanfar

22
"Soyut statik" kavramı OO ilkelerinin ihlali midir?
Trevor

7
@ threed, Hiç değil, ama elbette sadece statickendi kavramının zaten bir ihlal olduğunu söyleyen insanlar var ....
Pacerier

4
Statik gereksinim, "OO ilkelerinin" her zaman iddia edildiği kadar kapsamlı olmadığını gösteren açık bir göstergedir.
Ben

147

Statik bir yöntemi geçersiz kılamazsınız, bu yüzden soyut yapmak anlamsız olur. Dahası, soyut bir sınıftaki statik bir yöntem, o sınıfa ait olan sınıfa değil, o sınıfa ait olacaktır, bu yüzden yine de kullanılamazdı.


18
Evet, statik yöntemlerin Java'da geçersiz kılınmaması gerçekten utanç verici.
Michel

12
@Michel: amaç ne olurdu? Örnek tabanlı davranış istiyorsanız, örnek yöntemlerini kullanın.
Ran Biron

8
Bu cevap yanlış. Soyut sınıflardaki statik yöntemler iyi çalışır ve yaygın olarak kullanılır. Sadece sınıfın kendisinin statik bir yöntemi soyut olmayabilir. @Michel, statik bir yöntemi geçersiz kılmak mantıklı değil. Bir örnek olmadan, çalışma zamanı hangi yöntemi çağırması gerektiğini nasıl bilebilir?
erickson

63
@erickson - Örnek olmadan bile, sınıf hiyerarşisi sağlamdır - statik yöntemlerde kalıtım, örnek yöntemlerinin kalıtımı gibi çalışabilir. Smalltalk bunu yapar ve oldukça faydalıdır.
Jared

8
@matiasg bu yeni bir şey değil. Soyut sınıfların her zaman statik, soyut olmayan yöntemlere sahip olmasına izin verilmiştir .
Matt Ball

70

abstractBir yönteme ek açıklama yöntemi alt sınıfta geçersiz kılınmalıdır belirtir.

Java'da, bir staticüye (yöntem veya alan) alt sınıflar tarafından geçersiz kılınamaz (bu, diğer nesne yönelimli dillerde mutlaka doğru değildir, bkz. SmallTalk.) Bir staticüye gizlenmiş olabilir , ancak bu geçersiz kılınandan temelde farklıdır .

Statik üyeler bir alt sınıfta geçersiz kılınamayacağından, abstractek açıklama onlara uygulanamaz.

Bir kenara, diğer diller tıpkı örnek miras gibi statik mirası desteklemektedir. Sözdizimi açısından bakıldığında, bu diller genellikle sınıf adının ifadeye dahil edilmesini gerektirir. Örneğin, Java'da, ClassA'da kod yazdığınızı varsayarsak, bunlar eşdeğer ifadelerdir (methodA () statik bir yöntemse ve aynı imzalı bir örnek yöntemi yoksa):

ClassA.methodA();

ve

methodA();

SmallTalk'ta, sınıf adı isteğe bağlı değildir, bu nedenle sözdizimi (SmallTalk'ın "konuyu" ve "fiili" ayırmak için.

ClassA methodA.

Sınıf adı her zaman gerekli olduğundan, yöntemin doğru "sürümü" her zaman sınıf hiyerarşisinde gezilerek belirlenebilir. Değeri ne staticolursa olsun, zaman zaman miras kaçırıyorum ve ilk başladığımda Java statik miras eksikliği tarafından ısırıldı. Buna ek olarak, SmallTalk ördek türündedir (ve böylece sözleşme-programını desteklemez.) Bu nedenle, abstractsınıf üyeleri için değiştirici yoktur .


1
"Statik üye alt sınıflar tarafından geçersiz kılınamaz" yanlış. En azından Java6'da mümkündür. Durumdan beri emin değilim.
Steven De Groote

15
@Steven De Groote Statik bir üye gerçekten alt sınıflar tarafından geçersiz kılınamaz. Bir alt sınıf, üst sınıftaki statik yöntemle aynı imzayla statik bir yönteme sahipse, bunu geçersiz kılmaz, gizler. http://docs.oracle.com/javase/tutorial/java/IandI/override.html Fark, polimorfizmin gizli yöntemler için değil, yalnızca geçersiz kılınması için çalışmasıdır.
John29

2
@ John29 Açıklama için teşekkürler, ancak adlandırma farkı dışında kullanımda benzer görünüyor.
Steven De Groote

2
@Steven De Groote Evet, kullanımda benzer, ancak davranış farklı. Statik soyut yöntemlerin olmamasının nedeni budur - polimorfizmi desteklemiyorlarsa statik soyut yöntemlerin anlamı nedir?
John29

3
@Steven De Groote: Üst sınıfın kendisinde bu yönteme bir çağrı yaptığınızda fark ortaya çıkar. Diyelim ki Super.foo, Super.bar'ı çağırır. Bir alt sınıf Subclass.bar uygular ve sonra foo çağırırsa, foo yine de Subclass.bar yerine Super.bar öğesini çağırır. Bu nedenle, gerçekten sahip olduğunuz şey, her ikisi de "bar" olarak adlandırılan tamamen farklı ve ilişkisiz iki yöntemdir. Herhangi bir anlamda bu geçersiz kılmıyor.
Doradus

14

Aynı soruyu da sordum, işte neden

Abstract sınıfı dediği gibi, uygulama vermeyecek ve alt sınıfın vermesine izin vermeyecektir.

bu yüzden Alt Sınıf, Üst Sınıf yöntemlerini geçersiz kılmak zorundadır,

KURAL NO 1 - Statik bir yöntem geçersiz kılınamaz

Statik üyeler ve yöntemler derleme zamanı öğeleri olduğundan, bu nedenle Statik yöntemlerin Aşırı Yüklemesine (Derleme zamanı Polimorfizmi) Geçersiz Kılma (Çalışma Zamanı Polimorfizmi) yerine izin verilir

Yani, Soyut olamazlar.

Soyut statik gibi bir şey yoktur <--- Java Universe'de izin verilmiyor


5
-1, "Java statik yöntemlerin geçersiz kılınmasına izin vermez, çünkü statik üyeler ve yöntemler derleme zaman öğeleriidir" doğru değildir. Statik tip kontrolü kesinlikle abstract staticbkz. Stackoverflow.com/questions/370962/… . Gerçek nedeni Java statik yöntemler geçersiz kılınan olmasına izin vermez, çünkü Java statik yöntemler geçersiz kılınan olmasına izin vermez nedeni budur.
Pacerier

Aşırı yüklemenin polimorfizmle ilgisi yoktur. Aşırı yükleme ve geçersiz kılmanın, Java ve JavaScript'in her ikisinde de "Java" olduğu gibi "over" önekinin ortak bir yanı yoktur. Bir yöntemin adı onu tanımlayan şey değil, imzasıdır. yani foo(String)aynı değil foo(Integer)- hepsi bu.
Kaptan Adam

@CaptainMan Aşırı yüklemeye kelimenin tam anlamıyla "parametrik polimorfizm" denir, çünkü parametrenin türüne bağlı olarak polimorfizm olan farklı bir yöntem çağrılır.
Davor

12

Bu korkunç bir dil tasarımı ve neden mümkün olamayacağına dair hiçbir sebep yok.

Aslında, burada nasıl bir uygulamasıdır CAN yapılabilir JAVA :

public class Main {

        public static void main(String[] args) {
                // This is done once in your application, usually at startup
                Request.setRequest(new RequestImplementationOther());

                Request.doSomething();
        }

        public static final class RequestImplementationDefault extends Request {
                @Override
                void doSomethingImpl() {
                        System.out.println("I am doing something AAAAAA");
                }
        }

        public static final class RequestImplementaionOther extends Request {
                @Override
                void doSomethingImpl() {
                        System.out.println("I am doing something BBBBBB");
                }
        }

        // Static methods in here can be overriden
        public static abstract class Request {

                abstract void doSomethingImpl();

                // Static method
                public static void doSomething() {
                        getRequest().doSomethingImpl();
                }

                private static Request request;
                private static Request getRequest() {
                        // If setRequest is never called prior, it will default to a default implementation. Of course you could ignore that too. 
                        if ( request == null ) {
                                return request = new RequestImplementationDefault();
                        }
                        return request;
                }
                public static Request setRequest(Request r){
                        return request = r;
                }

        }
}

================= Aşağıdaki eski örnek ==================

GetRequest öğesini arayın ve çağrı yapılmadan önce uygulamayı değiştirmek için getRequestImpl ... setInstance çağrılabilir.

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * @author Mo. Joseph
 * @date 16 mar 2012
 **/

public abstract class Core {


    // ---------------------------------------------------------------        
    private static Core singleton; 
    private static Core getInstance() {
        if ( singleton == null )
            setInstance( new Core.CoreDefaultImpl() );  // See bottom for CoreDefaultImpl

        return singleton;
    }    

    public static void setInstance(Core core) {
        Core.singleton = core;
    }
    // ---------------------------------------------------------------        



    // Static public method
    public static HttpServletRequest getRequest() {      
        return getInstance().getRequestImpl();
    }


    // A new implementation would override this one and call setInstance above with that implementation instance
    protected abstract HttpServletRequest getRequestImpl();




    // ============================ CLASSES =================================

    // ======================================================================
    // == Two example implementations, to alter getRequest() call behaviour 
    // == getInstance() have to be called in all static methods for this to work
    // == static method getRequest is altered through implementation of getRequestImpl
    // ======================================================================

    /** Static inner class CoreDefaultImpl */
    public static class CoreDefaultImpl extends Core { 
        protected HttpServletRequest getRequestImpl() {
            return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        }
    }

     /** Static inner class CoreTestImpl : Alternative implementation */
    public static class CoreTestImpl extends Core { 
        protected HttpServletRequest getRequestImpl() {
            return new MockedRequest();
        }
    }       

}

Aşağıdaki gibi kullanılır:

static {
     Core.setSingleton(new Core.CoreDefaultImpl());

     // Or

     Core.setSingleton(new Core.CoreTestImpl());

     // Later in the application you might use

     Core.getRequest(); 

}

6
abstract staticSoruda sorulduğu gibi bir yöntem örneği nereden sağladığınızı anlamadım ve kalın yazdınız JAVA'DA YAPILABİLİRSİNİZ . Bu tamamen yanlış yönlendirici.
Blip

1
Kendi başına soyut statik olarak tanımlamanıza izin vermez, ancak benzer bir sonuç elde edebilirsiniz, böylece bu modeli / hack'i kullanarak s statik yönteminin uygulamasını değiştirebilirsiniz. Çok yanlış yönlendirilmiş. Bu yapılabilir, ancak farklı anlambilim kullanarak.
mmm

Bu, soyut bir sınıfı genişletmenin, ardından statik yöntemleri alt öğeye koymanın bir örneğidir. Bu, herhangi bir şekilde JAVA'DA YAPILABİLECEĞİN bir örneği değildir.
Tüplü Steve

2
@ScubaSteve İlk olarak, sonucunuzda yanılıyorsunuz. İkincisi, aynı sonucu elde eder. Yani bir sınıfa statik erişim başka bir uygulama ile değiştirilebilir. Statik anahtar kelimeyi soyutlanabilir yaptığımı söylemenin bir cevabı değil, ancak bu kalıbı kullanarak statik yöntemleri kullanabilir ve uygulamalarını değiştirebilirsiniz. Ancak küresel olmanın olumsuz etkisi vardır, ancak bir test / prod / dev ortamı için bu bizim için hile yapar.
mmm

5
  • Soyut bir yöntem yalnızca bir alt sınıfta geçersiz kılınabilmesi için tanımlanır. Ancak, statik yöntemler geçersiz kılınamaz. Bu nedenle, soyut, statik bir yönteme sahip olmak derleme zamanı hatasıdır.

    Şimdi bir sonraki soru neden statik yöntemler geçersiz kılınamaz?

  • Çünkü statik yöntemler örneğine değil, belirli bir sınıfa aittir. Statik bir yöntemi geçersiz kılmaya çalışırsanız, herhangi bir derleme veya çalışma zamanı hatası almayacaksınız, ancak derleyici statik üst sınıf statik yöntemini gizleyecektir.


4

Statik bir yöntemin tanım gereği bilmesi gerekmez this. Bu nedenle, sanal bir yöntem olamaz (bu, mevcut alt sınıf bilgilerine göre aşırı yüklenir)this ); bunun yerine, statik yöntem aşırı yüklemesi yalnızca derleme zamanında mevcut olan bilgilere dayanır (bunun anlamı: statik bir üst sınıf yöntemine başvurduğunuzda, üst sınıf yöntemini çağırırsınız, ancak hiçbir zaman bir alt sınıf yöntemini çağırmazsınız).

Buna göre, soyut statik yöntemler oldukça işe yaramaz çünkü referansını asla tanımlanmış bir bedenle değiştirmeyeceksiniz.


4

Görüyorum ki zaten bir tanrı-milyon yanıt var ama pratik çözüm görmüyorum. Tabii ki bu gerçek bir problem ve bu sözdizimini Java'da hariç tutmak için iyi bir neden yok. Orijinal soru, bunun gerekli olabileceği bir bağlamdan yoksun olduğundan, hem bir bağlam hem de bir çözüm sağlarım:

Aynı sınıfta bir grup statik yönteminiz olduğunu varsayalım. Bu yöntemler sınıfa özgü statik bir yöntemi çağırır:

class C1 {
    static void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }
    private static void doMoreWork(int k) {
        // code specific to class C1
    }
}
class C2 {
    static void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }
    private static void doMoreWork(int k) {
        // code specific to class C2
    }
}

doWork()C1ve C2içindeki yöntemler aynıdır. Bu calsseslerin birçoğu olabilir: C3 C4vb. static abstractİzin verildiyse , aşağıdaki gibi bir şey yaparak yinelenen kodu ortadan kaldırırsınız:

abstract class C {
    static void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }

    static abstract void doMoreWork(int k);
}

class C1 extends C {
    private static void doMoreWork(int k) {
        // code for class C1
    }
}

class C2 extends C {
    private static void doMoreWork(int k) {
        // code for class C2
    }
}

ancak bu, derlemeye static abstractizin verilmediği için derlenmez . Bununla birlikte, bu static classizin verilen yapı ile atlatılabilir :

abstract class C {
    void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }
    abstract void doMoreWork(int k);
}
class C1 {
    private static final C c = new  C(){  
        @Override void doMoreWork(int k) {
            System.out.println("code for C1");
        }
    };
    public static void doWork() {
        c.doWork();
    }
}
class C2 {
    private static final C c = new C() {
        @Override void doMoreWork(int k) {
            System.out.println("code for C2");
        }
    };
    public static void doWork() {
        c.doWork();
    }
}

Bu çözüm ile çoğaltılan tek kod

    public static void doWork() {
        c.doWork();
    }

1
Nihai çözümünüzde soyut C sınıfında herhangi bir statik yöntem bulunmadığından, neden C1 ve C2'nin onu genişletmesine ve doMoreWork () yöntemini geçersiz kılmasına ve diğer sınıfların örneğini oluşturmasına ve gerekli yöntemleri çağırmasına izin vermeyin. Temel olarak anonim bir sınıf kullanarak sınıf C'yi genişletmek ve daha sonra statik bir yöntemden erişime izin vermek için statik örneğini kullanarak C1 ve C2'de aynı işlemi gerçekleştiriyorsunuz, ancak bu gerekli değildir.
sactiw

Burada sağladığınız içeriği anlamıyorum. Nihai çözümünüzde yapabileceğiniz şey aramak C1.doWork()ya da C2.doWork()Ama arayamazsınız C.doWork(). Ayrıca, sağladığınız örnekte, çalışmayan, izin verilip verilmediğini varsayalım, sınıfın Cuygulanmasını nasıl bulacaktır doMoreWork()? Sonunda bağlam kodunuza kötü tasarım diyorum. Neden? basitçe, kod için ortak bir işlev oluşturmak ve sonra sınıfta statik bir işlev uygulamak yerine benzersiz bir kod yaratmış olmanızdır C. Bu daha kolay !!!
Blip

2

Varsayalım ki iki sınıf vardır Parentve Child. Parentolduğunu abstract. Beyanlar aşağıdaki gibidir:

abstract class Parent {
    abstract void run();
}

class Child extends Parent {
    void run() {}
}

Herhangi örneği olduğunu bu araçlar Parentnasıl belirtmelisinizrun() yürütüleceğini .

Ancak, şimdi öyle Parentolmadığını varsayalım abstract.

class Parent {
    static void run() {}
}

Bunun anlamı şudur ki Parent.run() , statik yöntemi çalıştıracağı .

An'un tanımı abstract yöntemin , "bildirilen ancak uygulanmayan bir yöntemdir", yani hiçbir şey döndürmez.

A'un tanımı static yöntemin , "çağrıldığı örnek ne olursa olsun aynı parametreler için aynı değeri döndüren bir yöntemdir".

abstractÖrnek değiştikçe bir yöntemin dönüş değeri değişecektir. Bir staticyöntem olmaz. birstatic abstract yöntem hemen hemen dönüş değeri sabit olan bir yöntemdir, ancak hiçbir şey döndürmez. Bu mantıklı bir çelişki.

Ayrıca, bir static abstractyöntemin gerçekten fazla bir nedeni yoktur .


2

Soyut bir sınıfın statik bir yöntemi olamaz çünkü statik yöntemler işlevlerine statik olarak bağlanırken DYNAMIC BINDING elde etmek için soyutlama yapılır. Statik yöntemler nesneye değil sınıfa aittir. Her nesne ile paylaşıldığı PERMGEN olarak bilinen bir bellek alanında saklanırlar. Soyut sınıftaki yöntemler işlevselliklerine dinamik olarak bağlanır.


1
Soyut sınıfların elbette statik yöntemleri olabilir. Ancak statik soyut yöntemler değil.
JacksOnF1re

2

Bir yöntemi staticaraç olarak tanımlamak , sınıf yöntemiyle bu yöntemi çağırabiliriz ve bu sınıf da varsa, abstractherhangi bir gövde içermediği için bu yöntemi çağırmanın bir anlamı yoktur ve bu nedenle bir yöntemi hem staticve olarak ilan edemeyiz abstract.


2

Soyut yöntemler sınıfa ait olduğundan ve uygulayıcı sınıf tarafından geçersiz kılınamayacağından, aynı imzalı statik bir yöntem olsa bile, yöntemi gizler, geçersiz kılmaz. Bu nedenle, soyut yöntemi asla vücudu alamayacağı kadar statik olarak ilan etmek önemsizdir.Bu nedenle, zaman hatasını derler.


1

Statik bir yöntem, sınıfın bir örneği olmadan çağrılabilir. Örneğinizde foo.bar2 () öğesini çağırabilirsiniz, ancak foo.bar () öğesini çağırabilirsiniz, çünkü bar için bir örneğe ihtiyacınız vardır. Aşağıdaki kod işe yarar:

foo var = new ImplementsFoo();
var.bar();

Statik bir yöntem çağırırsanız, her zaman aynı kod yürütülür. Yukarıdaki örnekte, ImplementsFoo'da bar2'yi yeniden tanımlasanız bile var.bar2 () öğesine yapılan bir çağrı foo.bar2 () işlemini yürütür.

Bar2'nin artık bir uygulaması yoksa (soyutun anlamı budur), bir yöntemi uygulama olmadan çağırabilirsiniz. Bu çok zararlı.


1
Ve soyut bir statik yöntem örnek olmadan çağrılabilir, ancak alt sınıfta bir uygulamanın oluşturulması gerekir. Tam olarak polimorfizm değil, ama etrafta dolaşmanın tek yolu, somut çocuğa "soyut statik" yöntemi "gerektiren" bir arayüz uygulamaktır. Dağınık ama uygulanabilir.
fijiaaron

3
aslında yanılmışım. Bir arabirimde de statik yöntemler bulunamaz. Dil hatası.
fijiaaron

1

Bu sorunun cevabını, bir arabirimin yöntemlerinin (bir ana sınıfta soyut yöntemler gibi çalışan) neden statik olamayacağı şeklinde bulduğuma inanıyorum. İşte tam cevap (benim değil)

Temel olarak statik yöntemler derleme zamanında bağlanabilir, çünkü bunları çağırmak için bir sınıf belirtmeniz gerekir. Bu, yöntemi çağırdığınız başvuru sınıfının derleme zamanında bilinmiyor olabileceği örnek yöntemlerden farklıdır (bu nedenle hangi kod bloğunun çağrıldığı yalnızca çalışma zamanında belirlenebilir).

Statik bir yöntem çağırıyorsanız, uygulandığı sınıfı veya doğrudan alt sınıflarını zaten biliyorsunuzdur. Eğer tanımlarsan

abstract class Foo {
    abstract static void bar();
}

class Foo2 {
    @Override
    static void bar() {}
}

O zaman herhangi bir Foo.bar();çağrı açıkça yasa dışıdır ve her zaman kullanacaksınız Foo2.bar();.

Bunu akılda tutarak, statik bir soyut yöntemin tek amacı, böyle bir yöntemi uygulamak için alt sınıfları zorlamak olacaktır. Başlangıçta bu çok yanlış olduğunu düşünebilir, ancak bir genel tür parametresi varsa <E extends MySuperClass>o arayüzü üzerinden bu teminat güzel olurdu Ekutu .doSomething(). Tür silme jeneriklerinin sadece derleme zamanında bulunduğunu unutmayın.

Peki, faydalı olur mu? Evet, ve belki de bu yüzden Java 8 arabirimlerde statik yöntemlere izin veriyor (yalnızca varsayılan bir uygulamada olsa da). Neden sınıflarda varsayılan bir uygulama ile soyut statik yöntemler? Çünkü varsayılan bir uygulamaya sahip soyut bir yöntem aslında somut bir yöntemdir.

Varsayılan uygulama olmadan neden özet / arabirim statik yöntemleri olmasın? Görünüşe göre, sadece Java'nın hangi kod bloğunu yürütmesi gerektiğini tanımlama biçiminden dolayı (cevabımın ilk kısmı).


1

Çünkü soyut sınıf bir OOPS kavramı ve statik üyeler OOPS'un bir parçası değildir ....
Şimdi şey şu ki, arabirimde statik tam yöntemler bildirebiliriz ve bir arabirim içindeki ana yöntemi bildirerek arabirimi yürütebiliriz

interface Demo 
{
  public static void main(String [] args) {
     System.out.println("I am from interface");
  }
}

0

Soyut bir statik yönteme sahip olma fikri, söz konusu soyut sınıfı doğrudan bu yöntem için kullanamayacağınızdır, ancak bu statik yöntemi (veya jenerikler için: genel jenerasyonun gerçek sınıfı) uygulamaya yalnızca ilk türev kullanımı).

Bu şekilde, örneğin sıralama seçeneklerinin parametrelerini tanımlayan bir sortableObject soyut sınıfı veya hatta (auto-) soyut statik yöntemlerle arabirim oluşturabilirsiniz:

public interface SortableObject {
    public [abstract] static String [] getSortableTypes();
    public String getSortableValueByType(String type);
}

Artık tüm bu nesneler için aynı olan ana türlere göre sıralanabilen sıralanabilir bir nesne tanımlayabilirsiniz:

public class MyDataObject implements SortableObject {
    final static String [] SORT_TYPES = {
        "Name","Date of Birth"
    }
    static long newDataIndex = 0L ;

    String fullName ;
    String sortableDate ;
    long dataIndex = -1L ;
    public MyDataObject(String name, int year, int month, int day) {
        if(name == null || name.length() == 0) throw new IllegalArgumentException("Null/empty name not allowed.");
        if(!validateDate(year,month,day)) throw new IllegalArgumentException("Date parameters do not compose a legal date.");
        this.fullName = name ;
        this.sortableDate = MyUtils.createSortableDate(year,month,day);
        this.dataIndex = MyDataObject.newDataIndex++ ;
    }
    public String toString() {
        return ""+this.dataIndex+". "this.fullName+" ("+this.sortableDate+")";
    }

    // override SortableObject 
    public static String [] getSortableTypes() { return SORT_TYPES ; }
    public String getSortableValueByType(String type) {
        int index = MyUtils.getStringArrayIndex(SORT_TYPES, type);
        switch(index) {
             case 0: return this.name ;
             case 1: return this.sortableDate ;
        }
        return toString(); // in the order they were created when compared
    }
}

Şimdi bir

public class SortableList<T extends SortableObject> 

türleri alabilir, sıralanacak bir tür seçmek için bir açılır menü oluşturabilir ve bu türden veri alarak listeye başvurabilir ve bir sıralama türü seçildiğinde otomatik olarak -yeni öğeleri sıralayın. SortableList örneğinin "T" statik yöntemine doğrudan erişebileceğini unutmayın:

String [] MenuItems = T.getSortableTypes();

Bir örneği kullanmakla ilgili sorun, SortableList öğesinde henüz öğe bulunmayabilir, ancak zaten tercih edilen sıralamayı sağlaması gerekir.

Cheerio, Olaf.


0

İlk olarak, soyut sınıflarla ilgili önemli bir nokta - Soyut bir sınıf somutlaştırılamaz (bkz. Wiki ). Yani, yaratamaz herhangi soyut bir sınıfın örneğini.

Şimdi, java'nın statik yöntemlerle ilgilenme yöntemi, yöntemi bu sınıfın tüm örnekleriyle paylaşmaktır .

Bu nedenle, bir sınıfı başlatamıyorsanız, soyut bir yöntem genişletilmeye çalıştığı için o sınıfın soyut statik yöntemleri olamaz.

Boom.


Soyut bir sınıftaki her yöntemin yine de yürütülmesi için sınıfının genişletilmesi gerekir, bu nedenle bu bir mazeret değildir. Soyut sınıfı genişletebilirsiniz (aynı zamanda soyut yöntemi uygulayarak). Yani bu bir açıklama olarak işe yaramıyor.
Pere

0

Java belgesine göre :

Statik yöntem, herhangi bir nesneyle değil, tanımlandığı sınıfla ilişkilendirilmiş bir yöntemdir. Sınıfın her örneği statik yöntemlerini paylaşır

Java 8'de, varsayılan yöntemlerle birlikte bir arabirimde statik yöntemlere de izin verilir. Bu, kütüphanelerimizde yardımcı yöntemler düzenlememizi kolaylaştırır. Bir arabirime özgü statik yöntemleri ayrı bir sınıftan ziyade aynı arabirimde tutabiliriz.

Buna güzel bir örnek:

list.sort(ordering);

onun yerine

Collections.sort(list, ordering);

Statik yöntemleri kullanmanın başka bir örneği de dokümanın kendisinde verilmiştir :

public interface TimeClient {
    // ...
    static public ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default public ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }    
}

0

Çünkü 'soyut', yöntemin geçersiz kılınması anlamına gelir ve 'statik' yöntemleri geçersiz kılamaz.


Bu yanıt, önceki yanıtların henüz ele almadığı hiçbir şey eklemez.
MarsAtomic

@MarsAtomic En çok oy alan cevaptan daha uygun olduğunu düşünüyorum. Ayrıca, kısa ve öz.
Praveen Kumar

Ardından, yeterli yanıtınız olduğunda bunları geliştirmek için önceki yanıtları düzenleyebilirsiniz. Tek yaptığınız, yinelenen cevaplar oluşturarak sinyale gürültü eklemektir. Lütfen Stack Overflow'un kendi kurallarınızı ve geleneklerinizi kendiniz oluşturmak ve herkesin takip etmesini beklemek yerine uygulayın.
MarsAtomic

Kabul etmiyorum, lütfen cevabımı diğerleriyle, özellikle de en çok oy alan cevapla karşılaştırın.
Praveen Kumar

"Bunu neden yapamıyorum?" Cevap: "çünkü yapamazsın".
JacksOnF1re

0

Düzenli yöntemler, alt sınıflar tarafından geçersiz kılınması ve işlevsellik sağlaması durumunda soyut olabilir. Sınıfın Foogenişlediğini düşününBar1, Bar2, Bar3 vb. . Yani, her birinin ihtiyaçlarına göre soyut sınıfın kendi versiyonu olacaktır.

Şimdi, tanım gereği statik yöntemler sınıfa aittir, sınıfın nesneleri veya alt sınıflarının nesneleri ile ilgisi yoktur. Var olmalarına bile gerek yok, sınıfları somutlaştırmadan kullanılabilirler. Bu nedenle, kullanıma hazır olmaları gerekir ve bunlara işlevsellik eklemek için alt sınıflara güvenemezler.


0

Özet, Abstract yöntemlerine uygulanan bir anahtar kelime olduğu için bir gövde belirtmez. Ve statik anahtar kelime hakkında konuşursak, bu sınıf alanına aittir.


lütfen cevabınız hakkında biraz ayrıntılı olun.
Blip

0

çünkü sınıfta herhangi bir statik üye veya statik değişken kullanıyorsanız sınıf yükleme zamanında yüklenir.


3
ve bu neden bir sorun olur?
eis

-1

Bunu Java 8'deki arabirimlerle yapabilirsiniz.

Bu konuda resmi belgeler:

https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html


2
Nasıl? Çözüm aradım ve bulamadım.
thouliha

Wut? Yapamazsın. Tüm statik arabirimler yöntemleri, arabirim sınıfı kullanılarak çağrılmalıdır.
mmm

8
Bu cevap yanlış ve java'da yeni insanlara yanlış yönlendiriyor. Bu, diğer yanıtlarda uygulanamayacağı ve belirtilemediği için soyut statik yöntemin herhangi bir örneğini gösterir
Blip

-1

Çünkü bir sınıf soyut bir sınıfı genişletirse, o zaman soyut yöntemleri geçersiz kılmak zorundadır ve bu zorunludur. Statik yöntemler derleme zamanında çözülen sınıf yöntemleri olduğu için geçersiz kılınmış yöntemler çalışma zamanında ve dinamik polimorfizmi takip eden örnek yöntemlerdir.


Lütfen bu karmaşayı büyük harfle yazın ve noktalayın.
Lorne Marquis
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.