Java arayüzünde neden statik bir yöntem tanımlayamıyorum?


499

EDIT: Java 8'den itibaren, arabirimlerde statik yöntemlere izin verilir.

İşte örnek:

public interface IXMLizable<T>
{
  static T newInstanceFromXML(Element e);
  Element toXMLElement();
}

Tabii ki bu işe yaramayacak. Ama neden olmasın?

Olası sorunlardan biri, aradığınızda ne olacağıdır:

IXMLizable.newInstanceFromXML(e);

Bu durumda, sadece boş bir yöntem (yani {}) çağırması gerektiğini düşünüyorum. Tüm alt sınıflar statik yöntemi uygulamaya zorlanır, bu nedenle statik yöntemi çağırırken hepsi iyi olur. Peki bu neden mümkün değil?

EDIT: Sanırım "çünkü Java bu şekilde" daha derin bir cevap arıyorum.

Statik yöntemlerin üzerine yazılamamasının belirli bir teknolojik nedeni var mı? Peki, Java tasarımcıları neden örnek yöntemleri geçersiz kılmaya karar verdiler, ancak statik yöntemleri değil?

EDIT: Tasarım ile ilgili sorun, bir kodlama kuralını zorlamak için arabirimler kullanmaya çalışıyorum.

Yani, arayüzün amacı iki yönlüdür:

  1. IXMLizable arabirimi bana (polimorfizm kullanarak, iyi çalışır) XML öğelerine uygulayan sınıfları dönüştürmek için izin istiyorum.

  2. Birisi IXMLizable arabirimini uygulayan yeni bir sınıf örneği oluşturmak istiyorsa, her zaman yeni birInstanceFromXML (Element e) statik yapıcısı olacağını bilir.

Bunu sağlamak için sadece arayüze yorum yapmaktan başka bir yol var mı?


4
Btw arabirimlerinde halka açık yöntem (ve alan) tanımlarını karıştırmanıza gerek yoktur.
Tom Hawtin - tackline

Hmm, stackoverflow.com/questions/21817/… 'nin bir kopyası gibi görünüyor . Bunu daha önce görmemiştim.
Michael Myers

1
Statik arayüz yöntemlerini nasıl kullanmak istediğinize dair bir kod verebilir misiniz?
Pavel Feldman

43
Bu, Java 8'de mümkün olacaktır: docs.oracle.com/javase/tutorial/java/IandI/…
dakshang

1
@dakshang Evet, ama OP'nin istediği şeyi yapmıyor.
user253751

Yanıtlar:


518

Java 8 statik arabirim yöntemlerine izin verir

Java 8 ile arayüzler olabilir statik yöntemler var. Ayrıca somut örnek yöntemlerine sahip olabilirler, ancak örnek alanlarına sahip olmayabilirler.

Burada gerçekten iki soru var:

  1. Neden kötü eski günlerde arayüzler statik yöntemler içeremedi?
  2. Statik yöntemler neden geçersiz kılınamıyor?

Arayüzlerde statik yöntemler

Önceki sürümlerde arabirimlerin statik yöntemlere sahip olamamasının güçlü bir teknik nedeni yoktu. Bu, yinelenen bir sorunun posteri ile güzel bir şekilde özetlenir . Statik arayüz yöntemleri başlangıçta küçük bir dil değişikliği olarak kabul edildi ve daha sonra bunları Java 7'ye eklemek için resmi bir teklif vardı , ancak daha sonra öngörülemeyen komplikasyonlar nedeniyle düştü.

Son olarak, Java 8, statik arabirim yöntemlerinin yanı sıra varsayılan bir uygulama ile geçersiz kılınabilir örnek yöntemlerini tanıttı. Yine de örnek alanları olamaz. Bu özellikler lambda ifade desteğinin bir parçasıdır ve bunlar hakkında daha fazla bilgiyi JSR 335'in H Bölümünde okuyabilirsiniz .

Statik yöntemleri geçersiz kılma

İkinci sorunun cevabı biraz daha karmaşıktır.

Statik yöntemler derleme zamanında çözülebilir. Dinamik dağıtım, örneğin, derleyicinin nesnenin somut türünü belirleyemediği ve dolayısıyla çağrılacak yöntemi çözemediği yöntemler için anlamlıdır. Ancak statik bir yöntem çağırmak bir sınıf gerektirir ve bu sınıf statik olarak - derleme zamanında - bilindiği için dinamik gönderme gereksizdir.

Burada neler olduğunu anlamak için örnek yöntemlerinin nasıl çalıştığına dair biraz arka plan gereklidir. Gerçek uygulama oldukça farklı olduğundan eminim, ancak davranışları doğru bir şekilde gözlemlediğimiz model gönderme yöntemini açıklayayım.

Her sınıfın, yöntemi uygulamak için yöntem imzalarını (ad ve parametre türleri) gerçek bir kod yığınıyla eşleyen bir karma tablosu olduğunu varsayın. Sanal makine bir örnek üzerinde bir yöntemi çağırmaya çalıştığında, nesneyi sınıfı için sorgular ve sınıfın tablosunda istenen imzayı arar. Bir yöntem gövdesi bulunursa çağrılır. Aksi takdirde, sınıfın üst sınıfı elde edilir ve arama burada tekrarlanır. Bu, yöntem bulunana kadar veya başka ana sınıf kalmayana kadar devam eder - bu da a sonucunu verir NoSuchMethodError.

Üst sınıf ve alt sınıfların her ikisi de tablolarında aynı yöntem imzası için bir giriş içeriyorsa, önce alt sınıfın sürümüyle karşılaşılır ve üst sınıfın sürümü hiçbir zaman kullanılmaz - bu bir "geçersiz kılma" dır.

Şimdi, nesne örneğini atladığımızı ve sadece bir alt sınıfla başladığımızı varsayalım. Çözünürlük yukarıdaki gibi devam edebilir ve size bir çeşit "geçersiz kılınabilir" statik yöntem sunar. Ancak, derleyici zamanında tüm olabilir, çünkü derleyici kendi sınıfı için belirtilmemiş türde bir nesneyi sorgulamak için çalışma zamanını beklemek yerine bilinen bir sınıftan başlar. İstenen sürümü içeren sınıfı her zaman belirtebildiğinden, statik bir yöntemi "geçersiz kılmanın" bir anlamı yoktur.


Yapıcı "arayüzler"

İşte soruya yönelik son düzenlemeyi ele almak için biraz daha malzeme.

Her uygulaması için etkili bir yapıcı benzeri bir yöntem uygulamak istediğiniz gibi görünüyor IXMLizable. Bir dakika boyunca bunu bir arayüzle uygulamaya çalışmayı unutun ve bu gereksinimi karşılayan bazı sınıflarınız olduğunu varsayalım. Nasıl kullanırdın?

class Foo implements IXMLizable<Foo> {
  public static Foo newInstanceFromXML(Element e) { ... }
}

Foo obj = Foo.newInstanceFromXML(e);

FooYeni nesneyi "oluştururken" somut türü açıkça adlandırmanız gerektiğinden, derleyici gerçekten gerekli fabrika yöntemine sahip olduğunu doğrulayabilir. Ve değilse, ne olacak? Bir uygulamaya Eğer IXMLizable"yapıcı" yoksun olduğunu, ve ben bir örneğini oluşturmak ve kod geçmek, bu ise bir IXMLizablegerekli tüm arayüz ile.

İnşaat, arayüzün değil uygulamanın bir parçasıdır . Arabirimle başarıyla çalışan herhangi bir kod yapıcıyı önemsemez. Yapıcıya önem veren herhangi bir kodun zaten beton türünü bilmesi gerekir ve arayüz göz ardı edilebilir.



12
# 1'in nedeni birden fazla miras olabilir mi? Birden fazla arabirimden miras alabileceğimiz için, iki arabirim aynı statik yöntem imzasını içeriyorsa ve sonra bir sınıf her ikisini de uyguladı ve bu yöntemi çağırdıysa, Java dil yaratıcılarının birden çok sınıf mirasına izin vermemekle işler karmaşıklaşabilir ilk sırada. Arayüz için hiçbir yöntem tanımına izin vermeyen aynı argüman yapılabilir.
shrini1000

1
@ shrini1000 - Hayır, statik yöntemler derleme zamanında çözümlenir. Belirsizlik sabitlerle aynı şekilde ele alınabilir: bir derleyici hatası ile. Ancak, Project Coin kapsamındaki teklif, öngörülemeyen zorluklardan dolayı reddedildi. Ne olduklarından emin değilim, ama bu çizgiler boyunca olduğunu sanmıyorum.
erickson

1
@ tgm1024 Evet, "Yapıcı 'arabirimleri'" bölümü derleme zamanında bilinen bir türle polimorfik davranışı çağırmanın neden mantıklı olmadığını açıklar. RESET()Belirli bir sınıfa nasıl girersiniz ? Sen yazardın SomeClass.RESET(). Dolayısıyla, bu API'yı tanımlamak için bir arayüze ihtiyacınız yoktur; statiktir. Arabirimler derleme zamanında beton türünü bilmediğinizde kullanılır. Statik bir yöntemde durum böyle değildir.
erickson

2
"İnşaat, arabirimin değil uygulamanın bir parçasıdır. Arabirimle başarılı bir şekilde çalışan herhangi bir kod yapıcıyı önemsemez." - Bu kesinlikle doğru değil. Diğer dillerde (örneğin Swift), statik olarak Tbilmeden yeni örnekler oluşturabilirim T, çünkü bir arayüzde belirli bir kurucunun (veya statik yöntemin) çalışma zamanında var olacağına söz veriyorum. Java'da neslin belirtilmesi imkansız olduğu, bunun anlamlı bir şey olmadığı anlamına gelmez.
Raphael

48

Bu zaten sorulmuş ve cevaplanmıştır, burada

Cevabımı çoğaltmak için:

Bir arabirimde statik bir yöntem bildirmenin hiçbir anlamı yoktur. Normal MyInterface.staticMethod () çağrısı ile yürütülemezler. Onları uygulayıcı sınıfı MyImplementor.staticMethod () belirterek çağırırsanız, gerçek sınıfı bilmeniz gerekir, bu nedenle arabirimin içerip içermediği önemsizdir.

Daha da önemlisi, statik yöntemler asla geçersiz kılmaz ve yapmaya çalışırsanız:

MyInterface var = new MyImplementingClass();
var.staticMethod();

statik kurallar, bildirilen var türünde tanımlanan yöntemin yürütülmesi gerektiğini söyler. Bu bir arayüz olduğundan, bu imkansız.

"Sonuç = MyInterface.staticMethod ()" yürütememenizin nedeni, MyInterface içinde tanımlanan yöntemin sürümünü yürütmek zorunda olmasıdır. Ancak MyInterface'te tanımlanmış bir sürüm olamaz, çünkü bu bir arayüzdür. Tanıma göre kodu yok.

Bunun "Java bu şekilde yaptığı" anlamına geldiğini söylese de, gerçekte karar, diğer tasarım kararlarının da mantıklı bir sonucudur ve aynı zamanda çok iyi bir nedendir.


14
<T MyInterface> öğesini genel bir tür parametresi olarak kullanırsanız, arabirim aracılığıyla T'nin .doSomething () yapabileceğini garanti etmek iyi olur.
Chris Betti

4
Argümanları anlıyorum, @Chris_Betti (jenerik olmayan tipler için bile) ile aynı fikirdeyim: kod yapısının bazı sınıfların belirli bir statik API'yi uygulamasını sağlaması güzel olurdu . Belki farklı bir konsept kullanmak mümkündür ...
Juh_

@Juh_, ..... veya kesinlikle gerekiyorsa yeni bir anahtar kelime. Ben staticyine de dillerde crummy bir terim olduğuna inanıyorum ve olduğu gibi uzatıldı. Yani kendi başına sahip olmak zaten kabataslak. Yukarıdaki örneğime bakın stackoverflow.com/questions/512877/… {shrug}.

3
Bu doğru görünmüyor: "Bir arabirimde statik bir yöntem bildirmenin hiçbir anlamı yoktur." Eğer somutlaştırılmadan bana bazı bilgiler sunabilecek bir sınıf koleksiyonum varsa, ancak bu statik sınıf düzeyi bilgilerini (yani, geçersiz kılınabilen statik yöntemle bir arayüz) koymak için ortak bir arayüze ihtiyacım var, o zaman geçerli bir kullanım . Nitelikler, yansıma vb.
Jason

1
"Bir arabirimde statik bir yöntem bildirmenin hiçbir anlamı yoktur." Bu doğru değil: sisteminizin varsayılan bir sınıf çözümleyicisine sahip olduğunu düşünün. ContainerInjectionInterce :: create (Container $ container) yöntemini uyguladığınızı algılarsa, örneğin bu işleve sahip nesneyi oluşturur.
user3790897

37

Normalde bu bir Fabrika deseni kullanılarak yapılır

public interface IXMLizableFactory<T extends IXMLizable> {
  public T newInstanceFromXML(Element e);
}

public interface IXMLizable {
  public Element toXMLElement();
}

7
+1 bir fabrika kalıbı soruna çözüm gibi geliyor. (soruya rağmen değil)
pvgoddijn

Birisi bana <T uzatır IXMLizable> koymanın anlamının ne olduğunu söyleyebilir. Java için yeniyim.Ne yapar?
Nuwan Harshakumara Piyarathna

1
@NuwanHarshakumaraPiyarathna T IXMLizable'ı genişleten bir sınıf olmalıdır. Bunun ne anlama geldiğini daha iyi anlamak için Java jeneriklerine bakın
adrian

37

Java 8'in ortaya çıkmasıyla artık arayüze varsayılan ve statik yöntemler yazmak mümkündür . docs.oracle/staticMethod

Örneğin:

public interface Arithmetic {

    public int add(int a, int b);

    public static int multiply(int a, int b) {
        return a * b;
    }
}
public class ArithmaticImplementation implements Arithmetic {

    @Override
    public int add(int a, int b) {
        return a + b;
    }

    public static void main(String[] args) {
        int result = Arithmetic.multiply(2, 3);
        System.out.println(result);
    }
}

Sonuç : 6

İPUCU: Statik arabirim yöntemini çağırmak için herhangi bir sınıfın uygulanması gerekmez. Elbette bu, üst sınıflardaki statik yöntemler için aynı kurallar, arabirimlerdeki statik yöntemler için geçerli olduğu için olur.


Bu, bu sorunun mükemmel bir örneğidir.

21

Çünkü alt sınıflarda statik yöntemler geçersiz kılınamaz ve bu nedenle soyut olamazlar. Ve bir arayüzdeki tüm yöntemler fiili , soyuttur.


2
Her türü her zaman herhangi bir statik arabirim yöntemi uygulamaya zorlayabilirsiniz. Tipik dersler, kimse?
MichaelGG

16
Kendinizin dışına çıkın ve şu soruyu cevaplayın: Neden statik yöntemler geçersiz kılınamaz? Statik yöntemler geçersiz kılsaydı, neye benzeyecekti? Onlarla ne yapabilirsin? Bu cevap temelde "Yapamazsınız çünkü yapamazsınız."
erickson

10

Java arayüzünde neden statik bir yöntem tanımlayamıyorum?

Aslında Java 8'de yapabilirsiniz.

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 bir arabirimin varsayılan yöntemleri ve statik yöntemleri olabilir . Bu, kütüphanelerimizde yardımcı yöntemler düzenlememizi kolaylaştırır. Bir arabirime özgü statik yöntemleri ayrı bir sınıfta değil aynı arabirimde tutabiliriz.

Varsayılan yöntem örneği:

list.sort(ordering);

onun yerine

Collections.sort(list, ordering);

Statik yöntem örneği ( doc'nin kendisinden):

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));
    }    
}

6

Arayüzler, sınıflara değil, nesne örneklerine doğal olarak bağlı olan polimorfizmle ilgilidir. Dolayısıyla statik bir arayüz bağlamında bir anlam ifade etmez.


Açık, özlü bir mantık. İyi koy.
Oke Uwechue

6

İlk olarak, tüm dil kararları dil yaratıcıları tarafından alınan kararlardır. Yazılım mühendisliği veya dil tanımlama veya derleyici / yorumlayıcı yazımı dünyasında, statik bir yöntemin bir arabirimin parçası olamayacağını söyleyen hiçbir şey yoktur. Onlar için birkaç dil oluşturdum ve derleyiciler yazdım - hepsi sadece oturup anlamlı anlambilim tanımlıyor. Bir arabirimdeki statik bir yöntemin anlambiliminin son derece açık olduğunu iddia ediyorum - derleyici yöntemin çalışma zamanı çözünürlüğünü ertelemek zorunda olsa bile.

İkincisi, statik yöntemler kullandığımız anlamına gelir, statik yöntemler içeren bir arayüz kalıbına sahip olmak için geçerli bir neden vardır - herhangi biriniz için konuşamam, ancak statik yöntemleri düzenli olarak kullanıyorum.

En olası doğru cevap, dilin tanımlandığı anda, arayüzlerdeki statik yöntemler için algılanan bir ihtiyaç olmadığıdır. Java yıllar içinde çok büyüdü ve bu görünüşte ilgi çeken bir öğe. Java 7'ye bakıldığında, dil değişikliğine neden olabilecek bir ilgi düzeyine yükseldiğini gösterir. Biri için, bir alt sınıfı örneğinde statik bir değişkene erişmek için statik olmayan getter yöntemimi çağırabildiğim için artık bir nesneyi başlatmam gerektiğinde mutlu olacağım ...


5

Statik yöntemler örnek yöntemleri gibi sanal değildir, bu yüzden Java tasarımcılarının arayüzlerde istemediklerine karar verdiklerini düşünüyorum.

Ancak, statik yöntemler içeren sınıfları arabirimlere koyabilirsiniz. Bunu deneyebilirsin!

public interface Test {
    static class Inner {
        public static Object get() {
            return 0;
        }
    }
}

5
  • "Statik yöntemlerin geçersiz kılınmasının özel bir nedeni var mı?"

Tanımları doldurarak bu soruyu sizin için yeniden ifade edeyim.

  • "Derleme zamanında çözülen yöntemlerin çalışma zamanında çözülememesinin belirli bir nedeni var mı?"

Ya da, daha eksiksiz bir şekilde ifade etmek gerekirse, bir örneği olmayan bir yöntemi çağırmak, ancak sınıfı bilmek istersem, sahip olmadığım örneğe dayalı olarak nasıl çözülmesini sağlayabilirim.


3

Birkaç cevap, geçersiz kılınabilen statik yöntemler kavramıyla ilgili sorunları tartıştı. Ancak bazen, sadece kullanmak istediğiniz gibi görünen bir desene rastlarsınız.

Örneğin, değer nesneleri olan, ancak değer nesnelerini işlemek için komutları olan bir nesne ilişkisel katmanı ile çalışıyorum. Çeşitli nedenlerle, her bir değer nesnesi sınıfı, çerçevenin komut örneğini bulmasına izin veren bazı statik yöntemler tanımlamak zorundadır. Örneğin, yapacağınız bir Kişiyi oluşturmak için:

cmd = createCmd(Person.getCreateCmdId());
Person p = cmd.execute();

ve bir Kişiyi kimliğine göre yüklemek için

cmd = createCmd(Person.getGetCmdId());
cmd.set(ID, id);
Person p = cmd.execute();

Bu oldukça uygundur, ancak sorunları vardır; özellikle statik yöntemlerin varlığı arayüzde uygulanamaz. Arayüzdeki geçersiz kılınabilir bir statik yöntem, sadece bir şekilde çalışabilseydi, tam olarak ihtiyacımız olan şey olurdu.

EJB'ler bu problemi bir Home arayüzü ile çözer; her nesne kendi Evini nasıl bulacağını bilir ve Ev "statik" yöntemleri içerir. Bu şekilde "statik" yöntemler gerektiğinde geçersiz kılınabilir ve normal ("Uzak" olarak adlandırılır) arabirimi çekirdeğinizin bir örneği için geçerli olmayan yöntemlerle karıştırmazsınız. Normal arayüzün bir "getHome ()" yöntemi belirtmesini sağlayın. Home nesnesinin bir örneğini döndürün (sanırım bir singleton olabilir) ve arayan tüm Person nesnelerini etkileyen işlemleri gerçekleştirebilir.


3

yorumlarında EDIT: As of Java 8, static methods are now allowed in interfaces.

Java 8'in arayüzlerde kullanılmasına izin verdiği için statik yöntemler doğrudur, ancak örneğiniz hala çalışmaz. Yalnızca statik bir yöntem tanımlayamazsınız: Uygulamanız gerekir veya bir derleme hatası alırsınız.


2

Jenerikler olmadan, statik arabirimler işe yaramaz çünkü tüm statik yöntem çağrıları derleme zamanında çözülür. Yani, onlar için gerçek bir faydası yok.

Jeneriklerle, varsayılan bir uygulama ile veya varsayılan uygulama olmadan kullanımları vardır. Açıkçası, geçersiz kılınması vb. Gerekecektir. Ancak, tahminimce bu kullanım çok OO değildi (diğer cevaplar obtus olarak belirtildiği gibi) ve bu nedenle yararlı bir şekilde uygulanması gereken çabaya değmez.


1
Jenerik ilaçların bununla ne ilgisi var? Bir arabirimdeki statik bir yöntem hala gerçekleştirilemez.
DJClayworth

Birincisi, bu bir uygulama kararı olurdu. Ama bir arayüzde statik yöntemler aramak istemediğini tahmin ediyorum (sadece bir sınıf kullanabilir). Ancak bunun yerine, bir tip sınıf gibi bir sorta veya tip parametrelerinin üzerinde bir şey istemektedir. Aslında, son düzenlemesi bunu daha da net bir şekilde gösteriyor.
MichaelGG

2
Why can't I define a static method in a Java interface?

Bir arabirimdeki tüm yöntemler açıkça soyuttur ve bu nedenle bunları statik olarak tanımlayamazsınız çünkü statik yöntemler soyut olamaz.


1

Bir arabirim asla statik olarak silinemez, örn ISomething.member. Bir arabirim her zaman arabirimin bir alt sınıfının bir örneğini ifade eden bir değişken aracılığıyla kayıttan çıkarılır. Bu nedenle, bir arabirim başvurusu alt sınıfının bir örneği olmadan hangi alt sınıfa başvurduğunu asla bilemez.

Dolayısıyla, bir arabirimdeki statik yönteme en yakın yaklaşım, "bunu" yok sayan, yani örneğin statik olmayan üyelerine erişmeyen statik olmayan bir yöntem olacaktır. Düşük seviyeli soyutlamada, statik olmayan her yöntem (herhangi bir vtable'a baktıktan sonra) gerçekten sadece sınıf kapsamına sahip, "this" i örtülü bir resmi parametre olarak alan bir işlevdir. Scala'nın tek nesnesini ve Java ile birlikte çalışabilirliği görünBu kavramın kanıtı olarak . Ve böylece her statik yöntem, "bu" parametresini almayan sınıf kapsamına sahip bir işlevdir. Bu nedenle, normal olarak statik bir yöntem statik olarak çağrılabilir, ancak daha önce belirtildiği gibi, bir arayüzün bir uygulaması yoktur (soyuttur).

Bu nedenle, bir arabirimdeki statik yönteme en yakın yaklaşımı elde etmek için statik olmayan bir yöntem kullanmaktır, ardından statik olmayan örnek üyelerinden hiçbirine erişmeyin. Başka hiçbir şekilde olası performans avantajı olmaz, çünkü statik olarak (derleme zamanında) bağlantı kurmanın bir yolu yoktur a ISomething.member(). Bir arabirimde statik bir yöntem gördüğüm tek yarar, örtük bir "bu" girdi (yani yoksaymak) ve böylece statik olmayan örnek üyelerin herhangi bir erişim izin vermemesidir. Bu, dolaylı olarak "buna" erişmeyen fonksiyonun değişmez olduğunu ve içerdiği sınıfa göre salt okunur olmadığını açıklar. Ancak bir arayüzde "statik" bildirimiISomething ona erişmeye çalışan insanları da karıştırır.ISomething.member()bu da derleyici hatasına neden olur. Derleyici hatası yeterince açıklayıcıysa, insanları burada yaptığımız gibi (görünüşte çoğunlukla fabrika yöntemleri), istedikleri şeyi gerçekleştirmek için statik olmayan bir yöntem kullanma konusunda eğitmeye çalışmaktan daha iyi olurdu (ve 3 yıldır tekrarlandı Bu sitede S ve C kez), bu yüzden birçok kişi için sezgisel olmayan bir konudur. Doğru anlayışı elde etmek için bir süre düşünmek zorunda kaldım.

Bir arabirimde değiştirilebilir bir statik alan elde etmenin yolu, alt sınıftaki statik alana erişmek için arabirimde statik olmayan alıcı ve ayarlayıcı yöntemlerini kullanmaktır. Sidenote, görünüşte değişmez statikler ile Java arayüzünde bildirilebilir static final.


0

Arayüzler sadece bir sınıfın sağlayacağı şeylerin bir listesini sağlar, bu şeylerin gerçek bir uygulamasını değil, statik öğeniz budur.

Statik istiyorsanız, soyut bir sınıf kullanın ve miras alın, aksi takdirde statiki kaldırın.

Umarım yardımcı olur!


2
Teorik olarak, statik bir davranış içerecek bir arayüz tanımlayabilirsiniz, yani, "bu arayüzün uygulamaları bu imzayla birlikte statik bir metot foo () içerir" ve uygulamayı belirli bir sınıfa bırakabilirsiniz. Bu davranışın yararlı olacağı durumlarla karşılaştım.
Rob

0

Bir arabirimde statik yöntemleri tanımlayamazsınız çünkü statik yöntemler sınıf örneğine değil sınıfa aittir ve arabirimler Sınıf değildir. Daha fazlasını buradan okuyun.

Ancak, isterseniz bunu yapabilirsiniz:

public class A {
  public static void methodX() {
  }
}

public class B extends A {
  public static void methodX() {
  }
}

Bu durumda sahip olduğunuz yöntem methodX () adı verilen 2 farklı statik yöntemle iki sınıftır.


0

Yapabileceğinizi varsayalım; bu örneği düşünün:

interface Iface {
  public static void thisIsTheMethod();
}

class A implements Iface {

  public static void thisIsTheMethod(){
    system.out.print("I'm class A");
  }

}

class B extends Class A {

  public static void thisIsTheMethod(){
    System.out.print("I'm class B");
  } 
}

SomeClass {

  void doStuff(Iface face) {
    IFace.thisIsTheMethod();
    // now what would/could/should happen here.
  }

}

1
"Ben A sınıfıyım" yazdıracaktı. Ancak, yazdıysanız A.thisIsTheMethod()"Ben B sınıfıyım" yazdıracaktır.
cdmckay

ama oyr arabirimdeki yöntemleri çağırmak (veya derleyici) hangi yöntemin çağrılması gerektiğini nasıl bileceksiniz? (rember Ifric uygulamak dricetly daha fazla sınıf olabilir
pvgoddijn

üzgünüm, demek istediğim: Ancak, eğer yazdıysanız B.thisIsTheMethod()"Ben B sınıfıyım" yazdıracaktır.
cdmckay

dedim IFace.thisIsTHeMethod bilerek çünkü orada sorun yatıyor. tanımlanmamış davranış olmadan arayüzde çağırmak mümkün olmayacaktı (açıklandığı halde)
pvgoddijn

0

Uygulanabilecek bir şey statik arabirimdir (arabirimdeki statik yöntem yerine). Belirli bir statik arabirimi uygulayan tüm sınıflar, karşılık gelen statik yöntemleri uygulamalıdır. Kullanarak herhangi bir Sınıf clazz statik arayüz SI alabilirsiniz

SI si = clazz.getStatic(SI.class); // null if clazz doesn't implement SI
// alternatively if the class is known at compile time
SI si = Someclass.static.SI; // either compiler errror or not null

sonra arayabilirsiniz si.method(params). Derleme zamanı bilinmeyen bir sınıftan SI statik yöntemler uygulamasını elde edebileceğinizden (veya uygulanmasını kontrol ettiğinizden) bu yararlı olacaktır (örneğin fabrika tasarım deseni için)! Dinamik bir dağıtım gereklidir ve bir sınıfın statik yöntemlerini (son değilse) genişleterek (statik arabirimden çağrıldığında) geçersiz kılabilirsiniz. Açıkçası, bu yöntemler sadece sınıflarının statik değişkenlerine erişebilir.


0

Java 8'in bu sorunu çözdüğünü fark etsem de, şu anda üzerinde çalıştığım bir senaryoyla (Java 7'yi kullanarak kilitli) bir arayüzde statik yöntemler belirleyebilmenin yararlı olacağını düşündüm.

Çeşitli nedenlerle değerleri değerlendirmek yardımcı yöntemler ile birlikte "id" ve "displayName" alanları tanımladığım birkaç numaralandırma tanımları var. Bir arabirim uygulamak, alıcı yöntemlerinin yerinde olmasını sağlar, ancak statik yardımcı yöntemlerin olmamasını sağlar. Bir enum olarak, yardımcı yöntemleri kalıtsal bir soyut sınıfa veya benzer bir şeye boşaltmanın gerçekten temiz bir yolu yoktur, bu nedenle yöntemler enumun kendisinde tanımlanmalıdır. Ayrıca bir numaralandırma olduğu için, bunu aslında bir örnek nesne olarak geçiremez ve arabirim türü olarak ele alamazsınız, ancak bir arabirim aracılığıyla statik yardımcı yöntemlerin varlığını gerektirebilmem, sevdiğim şeydir Java 8'de desteklenmektedir.

İşte amacımı gösteren kod.

Arayüz tanımı:

public interface IGenericEnum <T extends Enum<T>> {
    String getId();
    String getDisplayName();
    //If I was using Java 8 static helper methods would go here
}

Bir enum tanımı örneği:

public enum ExecutionModeType implements IGenericEnum<ExecutionModeType> {
    STANDARD ("Standard", "Standard Mode"),
    DEBUG ("Debug", "Debug Mode");

    String id;
    String displayName;

    //Getter methods
    public String getId() {
        return id;
    }

    public String getDisplayName() {
        return displayName;
    }

    //Constructor
    private ExecutionModeType(String id, String displayName) {
        this.id = id;
        this.displayName = displayName;
    }

    //Helper methods - not enforced by Interface
    public static boolean isValidId(String id) {
        return GenericEnumUtility.isValidId(ExecutionModeType.class, id);
    }

    public static String printIdOptions(String delimiter){
        return GenericEnumUtility.printIdOptions(ExecutionModeType.class, delimiter);
    }

    public static String[] getIdArray(){
        return GenericEnumUtility.getIdArray(ExecutionModeType.class);
    }

    public static ExecutionModeType getById(String id) throws NoSuchObjectException {
        return GenericEnumUtility.getById(ExecutionModeType.class, id);
    }
}

Genel numaralandırma yardımcı programı tanımı:

public class GenericEnumUtility {
    public static <T extends Enum<T> & IGenericEnum<T>> boolean isValidId(Class<T> enumType, String id) {       
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(enumOption.getId().equals(id)) {
                return true;
            }
        }

        return false;
    }

    public static <T extends Enum<T> & IGenericEnum<T>> String printIdOptions(Class<T> enumType, String delimiter){
        String ret = "";
        delimiter = delimiter == null ? " " : delimiter;

        int i = 0;
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(i == 0) {
                ret = enumOption.getId();
            } else {
                ret += delimiter + enumOption.getId();
            }           
            i++;
        }

        return ret;
    }

    public static <T extends Enum<T> & IGenericEnum<T>> String[] getIdArray(Class<T> enumType){
        List<String> idValues = new ArrayList<String>();

        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            idValues.add(enumOption.getId());
        }

        return idValues.toArray(new String[idValues.size()]);
    }

    @SuppressWarnings("unchecked")
    public static <T extends Enum<T> & IGenericEnum<T>> T getById(Class<T> enumType, String id) throws NoSuchObjectException {
        id = id == null ? "" : id;
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(id.equals(enumOption.getId())) {
                return (T)enumOption;
            }
        }

        throw new NoSuchObjectException(String.format("ERROR: \"%s\" is not a valid ID. Valid IDs are: %s.", id, printIdOptions(enumType, " , ")));
    }
}

0

Diyelim ki arabirimlerde statik yöntemlere izin verildi: * Tüm uygulayıcı sınıfları bu yöntemi bildirmeye zorlarlar. * Arayüzler genellikle nesneler aracılığıyla kullanılır, bu yüzden bunlardaki tek etkili yöntemler statik olmayan yöntemler olacaktır. * Belirli bir arabirimi bilen herhangi bir sınıf statik yöntemlerini çağırabilir. Bu nedenle, bir uygulayıcı sınıfın statik yöntemi altına çağrılır, ancak invoker sınıfı hangisini bilmez. Nasıl bilebilirim? Bunu tahmin etmek için hiçbir örneği yok!

Nesnelerle çalışırken arayüzlerin kullanıldığı düşünülüyordu. Bu şekilde, bir nesne belirli bir sınıftan somutlaştırılır, böylece bu son madde çözülür. Çağıran sınıfın hangi sınıfın olduğunu bilmesine gerek yoktur çünkü örnekleme üçüncü bir sınıf tarafından yapılabilir. Böylece, çağıran sınıf sadece arayüzü bilir.

Bunun statik yöntemlere genişletilmesini istiyorsak, daha önce bir uygulayıcı sınıf tanımlayabilmemiz ve ardından çağıran sınıfa bir referans iletebilmemiz gerekir. Bu, arabirimdeki statik yöntemlerle sınıfı kullanabilir. Fakat bu referans ile bir nesne arasındaki fark nedir? Sadece sınıfın ne olduğunu temsil eden bir nesneye ihtiyacımız var. Şimdi, nesne eski sınıfı temsil eder ve eski statik yöntemleri içeren yeni bir arabirim uygulayabilir - bunlar artık statik değildir.

Metaclasses bu amaca hizmet eder. Java sınıfını deneyebilirsiniz. Ancak sorun, Java'nın bunun için yeterince esnek olmamasıdır. Bir arabirimin sınıf nesnesinde bir yöntem bildiremezsiniz.

Bu bir meta sorun - kıçını yapmanız gerektiğinde

... filan filan

yine de kolay bir çözüm var - yöntemi aynı mantıkla statik olmayan hale getirmek. Ama sonra yöntemi çağırmak için önce bir nesne oluşturmanız gerekir.


0

Bunu çözmek için: hata: yöntem gövdesi eksik veya soyut statik void main (String [] args) bildir;

interface I
{
    int x=20;
    void getValue();
    static void main(String[] args){};//Put curly braces 
}
class InterDemo implements I
{
    public void getValue()
    {
    System.out.println(x);
    }
    public static void main(String[] args)
    {
    InterDemo i=new InterDemo();
    i.getValue();   
    }

}

çıktı: 20

Şimdi arayüzde statik yöntem kullanabiliriz


1
Yine de bu işe yaramaz. Bir arabirimde statik bir yöntem tanımlamak, bu arabirimi uygulayan sınıflarda başka tanımları zorunlu kılmaz. Statik yöntemi arayüz I'den tamamen kaldırırsanız, kodunuz derlenecek ve sorunsuz bir şekilde çalışacaktır. Başka bir deyişle, InterDemo sınıfında I arabiriminin ana yöntemini geçersiz kılmıyor, sadece aynı imzayla yeni bir yöntem oluşturuyorsunuz.
Fran Marzoa

-2

Java'nın statik arabirim yöntemleri olmadığını düşünüyorum çünkü onlara ihtiyacınız yok. Yaptığını düşünebilirsin, ama ... Onları nasıl kullanırdın? Onları şöyle çağırmak istersen

MyImplClass.myMethod()

arayüzde bildirmeniz gerekmez. Onları şöyle çağırmak istersen

myInstance.myMethod()

o zaman statik olmamalıdır. Aslında ilk yolu kullanacaksanız, ancak her bir uygulamanın böyle bir statik yönteme sahip olmasını sağlamak istiyorsanız, o zaman gerçekten bir kodlama kuralıdır, bir arayüz ve çağrı kodu uygulayan örnek arasında bir sözleşme değildir.

Arabirimler, arabirimi uygulayan sınıf örneği ile arama kodu arasında sözleşme tanımlamanızı sağlar. Ve java, bu sözleşmenin ihlal edilmediğinden emin olmanıza yardımcı olur, bu nedenle ona güvenebilirsiniz ve bu sözleşmeyi hangi sınıfın uyguladığından endişelenmeyin, sadece "sözleşme imzalayan biri" yeterlidir. Statik arayüzlerde kodunuz

MyImplClass.myMethod()

her arayüz uygulamasının bu yönteme sahip olduğuna güvenmez, bu yüzden ondan emin olmanıza yardımcı olmak için java'ya ihtiyacınız yoktur.


-5

Arayüzde statik yönteme ihtiyaç duyulan şey, temelde nesnenin bir örneğini oluşturmak zorunda olmadığınızda statik yöntemler kullanılır. Arayüzün tüm fikri, kavramdan saptırdığınız statik yöntemin tanıtılmasıyla OOP kavramlarını getirmektir.

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.