Bir arabirimde neden statik yöntemler bildiremiyorum?


150

Konu en çok anlatıyor - statik yöntemlerin bir arabirimde bildirilememesinin nedeni nedir?

public interface ITest {
    public static String test();
}

Yukarıdaki kod bana şu hatayı veriyor (en azından Eclipse'de): "ITest.test () arabirim yöntemi için geçersiz değiştirici; yalnızca genel ve soyut izin verilir".


2
Lütfen kusurlu olduğu için Espo'nun cevabını kabul etmeyin. Bir arabirim, statik bir yöntemin uygulanmasını içerebilecek bir sınıf dosyasına sahiptir (Java tasarımcısı buna izin verirse), bu nedenle statik yöntemin uygulanmasının çözümlenmesinde sorun yoktur. Diğer statik sınıflarda olduğu gibi çalışır.
Mnementh

"erickson" tarafından verilen cevaba katılıyorum stackoverflow.com/questions/512877/…
Maverick

9
Bu, Java 8 btw'de kullanılabilir.
m0skit0

1
@Nadorquest GIYF ama yine de, buraya bakın
m0skit0

2
Resmi belgelerden bağlantılar: Java SE eğitimi ve Java Dil Özellikleri 9.2
LoganMzz

Yanıtlar:


85

Burada birkaç sorun var. Birincisi, statik bir yöntemi tanımlamadan bildirme konusudur. Bu arasındaki fark

public interface Foo {
  public static int bar();
}

ve

public interface Foo {
  public static int bar() {
    ...
  }
}

Birincisi Espo'nun bahsettiği nedenlerden dolayı imkansız : hangi uygulayıcı sınıfın doğru tanım olduğunu bilmiyorsunuz.

Java olabilir ikincisi izin; ve aslında, Java 8'den başlayarak, öyle!


2
Evet - teknik değil fikirsel. Bunu istememin sebebi. bir arabirimde yalnızca arabirimde sınıfları uygulayarak kolayca yeniden kullanılabilen diğer "arabirim" yöntemlerine başvuruda bulunan statik bir "uygulama" yöntemi olabilir. Ancak bir arabirimde statik bir sınıf bildirilebilir , böylece
MyInterface.Impl.doIt

9
Java 8'den beri static, bir interface. Yöntemler olmalı public.
Olivier Grégoire

4
@ OlivierGrégoire ... ve kalıtsal değiller, ki bu anahtar.
William F. Jameson

1
İyi cevap, ama "yaklaşık eşdeğer" ROFLMAO xD Ben daha "biraz benzer" gibi koymak olurdu.
Timo

44

Bir arabirimde statik bir yönteme sahip olmamanızın nedeni, Java'nın statik başvuruları çözme biçiminde yatmaktadır. Java, statik bir yöntem yürütmeye çalışırken bir sınıf örneği aramaya zahmet etmez. Bunun nedeni, statik yöntemlerin örneğe bağımlı olmaması ve dolayısıyla doğrudan sınıf dosyasından yürütülebilmesidir. Bir arabirimdeki tüm yöntemlerin soyut olduğu göz önüne alındığında, VM'nin çalıştırılabilmesi için statik yöntemin arkasındaki kodu bulmak için arabirimin belirli bir uygulamasını araması gerekir. Bu daha sonra statik yöntem çözümlemesinin nasıl çalıştığı ile çelişir ve dile tutarsızlık getirir.


3
Bu açıklama sorunu açıklamıyor. Her arabirimin kendi sınıf dosyası vardır, statik yöntemi içerebilir. Bu nedenle, belirli bir uygulama için arama yapılması gerekmeyecektir.
Mnementh

Java'daki her arabirim türü kendi dosyasında değildir ve JLS'ye göre olmamalıdır. Buna ek olarak JLS, sınıfların her zaman tam tersine bir dosya sistemi ile depolanması gerektiğini şart koşmamaktadır.
Vlad Gudim

4
@Totophil: Arabirimler tek bir java dosyasında olmamalı, ancak derlendikten sonra kendi sınıf dosyalarına sahip olacaktır. Ben de yazdım.
Mnementh

18

Sorunuzu bir örnekle cevaplayacağım. Varsayalım, statik yöntem eklenmiş bir Math sınıfımız vardı. Bu yöntemi şöyle adlandırırsınız:

Math.add(2, 3);

Math, sınıf yerine bir arabirim olsaydı, tanımlanmış bir işlevi olamazdı. Bu nedenle, Math.add (2, 3) gibi bir şey söylemek mantıklı değil.


11

Nedeni tasarım ilkesinde yatmaktadır, java çoklu kalıtıma izin vermez. Birden fazla miras sorunu aşağıdaki örnekle gösterilebilir:

public class A {
   public method x() {...}
}
public class B {
   public method x() {...}
}
public class C extends A, B { ... }

Şimdi Cx () çağırırsanız ne olur? Ax () veya Bx () yürütülecek mi? Birden fazla mirasa sahip her dil bu sorunu çözmek zorundadır.

Arabirimler Java'da bir çeşit kısıtlı çoklu kalıtım sağlar. Yukarıdaki problemden kaçınmak için yöntemlerine izin verilmez. Arayüzler ve statik yöntemlerle aynı soruna bakarsak:

public interface A {
   public static method x() {...}
}
public interface B {
   public static method x() {...}
}
public class C implements A, B { ... }

Aynı sorun burada, Cx () çağırırsanız ne olur?


Downvote için herhangi bir neden var mı? Açıklayıcı bir yorum iyi olurdu.
Mnementh

Ben downvoter değilim, ama bu statik olmayan yöntemler için de geçerli değil mi?
nawfal

Tamam, işte iki farklı olasılık. Bir yöntem uygulanabilir veya yalnızca bildirilebilir. Statik yöntemin uygulanması gerektiğini anladım. Bu anlamda cevabımda sunulan problemle karşılaşıyorum. Bunu yapmazsanız, Espo'nun tarif ettiği problemle karşılaşırsınız - ve anlamadım çünkü statik yöntemin uygulanacağını varsaydım. Ayrıca bu nedenle statik bir soyut yöntem bildiremezsiniz, deneyin, derleyici şikayet edecektir.
Mnementh

Tamam, uygulama bölümünü unutun. soru neden ilan edemiyoruz. evet derleyici şikayet edecek ve neden soru budur. cevap verdiğini sanmıyorum.
nawfal

1
Nasıl durum arayüzüne sahip daha kötü olacağını Aiçeren int x(int z);ve arayüz Biçeren string x(int x);? x(3)C arayüzünde anlamı nedir ?
supercat

7

Statik yöntemler örnek yöntemler değildir. Örnek bir bağlam yoktur, bu yüzden onu arayüzden uygulamak çok az mantıklıdır.


5

Artık Java8, Arayüzdeki Statik Yöntemleri bile tanımlamamıza izin veriyor.

interface X {
    static void foo() {
       System.out.println("foo");
    }
}

class Y implements X {
    //...
}

public class Z {
   public static void main(String[] args) {
      X.foo();
      // Y.foo(); // won't compile because foo() is a Static Method of X and not Y
   }
}

Not: Varsayılan / statik anahtar kelimelerini varsayılan yöntemler ve Statik yöntemler için yapmak için açıkça kullanmazsak, Arayüzdeki yöntemler varsayılan olarak yine de genel olarak özetlenir.


4

Burada sorunuzun çok hoş ve özlü bir cevabı var . (Bunu açıklamak için bu kadar basit ve açık bir yol olarak beni etkiledi.)


Bu sorunun cevabı değil, en iyisi bir yorum olmalı.
CubeJockey

3

Görünüşe göre arayüzdeki statik yöntem Java 8'de desteklenebilir , benim çözümüm sadece iç sınıfta tanımlamak.

interface Foo {
    // ...
    class fn {
        public static void func1(...) {
            // ...
        }
    }
}

Aynı teknik ek açıklamalarda da kullanılabilir:

public @interface Foo {
    String value();

    class fn {
        public static String getValue(Object obj) {
            Foo foo = obj.getClass().getAnnotation(Foo.class);
            return foo == null ? null : foo.value();
        }
    }
}

İç sınıfa her zaman Interface.fn...yerine şeklinde erişilmelidir Class.fn..., o zaman belirsiz problemden kurtulabilirsiniz.


2

Arabirim, türler için değil, Nesneler için geçerli olan polimorfizm için kullanılır. Bu nedenle (daha önce belirtildiği gibi), statik bir arabirim üyesine sahip olmak mantıklı değildir.


Bazı yansıtıcı bağlamlarda neredeyse mantıklı görünüyor
Cruncher

1

Java 8 Dünyayı değiştirmişti, arayüzde statik yöntemlere sahip olabilirsiniz, ancak sizi bunun için uygulama sağlamaya zorlar.

public interface StaticMethodInterface {
public static int testStaticMethod() {
    return 0;
}

/**
 * Illegal combination of modifiers for the interface method
 * testStaticMethod; only one of abstract, default, or static permitted
 * 
 * @param i
 * @return
 */
// public static abstract int testStaticMethod(float i);

default int testNonStaticMethod() {
    return 1;
}

/**
 * Without implementation.
 * 
 * @param i
 * @return
 */
int testNonStaticMethod(float i);

}


0

Değiştiricilerin geçersiz kombinasyonu: statik ve soyut

Bir sınıfın üyesi statik olarak bildirilirse, nesne oluşturmadan o sınıfla sınırlanmış sınıf adıyla kullanılabilir.

Bir sınıfın üyesi soyut olarak bildirilirse, sınıfı soyut olarak bildirmeniz ve soyut üyenin miras alınan sınıfta (Alt Sınıf) uygulanmasını sağlamanız gerekir.

Alt sınıftaki bir sınıfın soyut üyesine statik yöntem davranışını değiştireceğiniz bir uygulama sağlamanız gerekir; bu da temel sınıfla sınırlı olan ve doğru olmayan soyut olarak bildirilir.


Bu soruya nasıl cevap veriyor? Sınıf hakkında yazarken OP arayüz hakkında sorular sordu.
Şanslı

0

Statik yöntemler miras alınamadığı için. Yani arayüze yerleştirmenin bir yararı yok. Arayüz temel olarak tüm abonelerinin takip etmesi gereken bir sözleşmedir. Arabirime statik bir yöntem yerleştirmek, aboneleri bunu uygulamaya zorlayacaktır. şimdi statik yöntemlerin kalıtsal olamayacağı gerçeğiyle çelişiyor.


statik yöntemler her zaman miras alınır ancak geçersiz kılınamazlar.
Akki

0

İle Java 8 , arabirimler artık statik yöntemlere sahip olabilir.

Örneğin, Karşılaştırıcı'nın statik bir naturalOrder () yöntemi vardır.

Arayüzlerin uygulamalara sahip olmaması şartı da ortadan kaldırılmıştır. Arabirimler artık bir istisna dışında normal uygulamalar gibi "varsayılan" yöntem uygulamalarını bildirebilir: hem bir arabirimden hem varsayılan bir uygulamayı hem de bir üst sınıftan normal bir uygulamayı devralıyorsanız, üst sınıfın uygulaması her zaman öncelik kazanacaktır.


AMAN TANRIM! Ciddi bir programcımız (ve ben, yorumcu) 10 yıllık bir soruya cevap veriyoruz (ve ben yorumluyorum).
Mohamed Anees A

Tarihi fark etmedim :)
Ishara

Haha! Sorun değil!
Mohamed Anees A

-2

Belki bir kod örneği yardımcı olur, ben C # kullanacağım, ama birlikte takip edebilmelidir.

IPayable adında bir arayüzümüz olduğunu varsayalım

public interface IPayable
{
    public Pay(double amount);
}

Şimdi, bu arayüzü uygulayan iki somut sınıfımız var:

public class BusinessAccount : IPayable
{
    public void Pay(double amount)
    {
        //Logic
    }
}

public class CustomerAccount : IPayable
{
    public void Pay(double amount)
    {
        //Logic
    }
}

Şimdi, çeşitli hesaplardan oluşan bir koleksiyonumuz olduğunu varsayalım, bunu yapmak için IPayable türünün genel bir listesini kullanacağız

List<IPayable> accountsToPay = new List<IPayable>();
accountsToPay.add(new CustomerAccount());
accountsToPay.add(new BusinessAccount());

Şimdi, tüm bu hesaplara 50,00 $ ödemek istiyoruz:

foreach (IPayable account in accountsToPay)
{
    account.Pay(50.00);
}

Şimdi arayüzlerin inanılmaz derecede faydalı olduğunu görüyorsunuz.

Yalnızca somut nesnelerde kullanılırlar. Statik sınıflarda değil.

Statik ödeme yaptıysanız, IPayable'ın hesaplar arasında dolaşırkenToPay, BusinessAcount veya CustomerAccount'ta ödeme çağırıp çağırmayacağını anlamanın bir yolu olmazdı.


Bu örnekte statik yöntemlerin bir anlamı olmadığı için, HERHANGİ bir örnekte anlamlı olmadıkları anlamına gelmez. Örneğinizde, IPayable arabiriminin kaç tane borç eklendiğini takip eden statik "IncrementPayables" yöntemi varsa, bu gerçek bir kullanım durumu olacaktır. Tabii ki, kişi her zaman soyut bir sınıf kullanabilirdi, ama ele aldığınız şey bu değil. Örneğiniz kendi başına arayüzlerdeki statik yöntemleri baltalamaz.
Cruncher
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.