Mengapa saya tidak dapat mendeklarasikan metode statis di antarmuka?

150

Topik mengatakan sebagian besar - apa alasan untuk fakta bahwa metode statis tidak dapat dideklarasikan dalam sebuah antarmuka?

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

Kode di atas memberi saya kesalahan berikut (setidaknya di Eclipse): "Pengubah ilegal untuk metode antarmuka ITest.test (); hanya publik & abstrak yang diizinkan".

Henrik Paul
sumber
2
Harap tidak menerima jawaban Espo, karena cacat. Antarmuka memiliki file kelas yang dapat berisi implementasi metode statis (jika perancang Java akan mengizinkan ini), sehingga tidak ada masalah dalam menyelesaikan implementasi metode statis. Ia bekerja persis seperti kelas-kelas statis lainnya.
Mnementh
saya agak setuju dengan jawaban yang diberikan oleh "erickson" stackoverflow.com/questions/512877/…
Maverick
9
Ini akan tersedia di Java 8 btw.
m0skit0
1
@Vadorequest GIYF tapi bagaimanapun, periksa di sini
m0skit0
2
Tautan dari dokumentasi resmi: Tutorial Java SE & Spesifikasi Bahasa Jawa 9.2
LoganMzz

Jawaban:

85

Ada beberapa masalah yang berperan di sini. Yang pertama adalah masalah mendeklarasikan metode statis tanpa mendefinisikannya. Inilah perbedaan antara

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

dan

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

Yang pertama tidak mungkin karena alasan yang disebutkan Espo : Anda tidak tahu kelas implementasi mana yang merupakan definisi yang benar.

Jawa bisa mengizinkan yang terakhir; dan sebenarnya, mulai di Java 8, ya!

James A. Rosen
sumber
2
Ya - itu ideologis, bukan teknis. Alasan saya menyukainya. bahwa seseorang dapat memiliki metode "implementasi" statis dalam suatu antarmuka yang hanya merujuk metode "antarmuka" lainnya dalam antarmuka yang dapat dengan mudah digunakan kembali dengan mengimplementasikan kelas. Tetapi seseorang dapat mendeklarasikan kelas statis dalam sebuah antarmuka sehingga orang dapat memiliki hal-hal seperti itu berada di sana seperti MyInterface.Impl.doIt (MyInterface i, Object [] args) {...}
peterk
9
Sejak Java 8, Anda bisa mendefinisikan staticmetode dalam interface. Metode harus public.
Olivier Grégoire
4
@ OlivierGrégoire ... dan mereka tidak diwarisi, yang merupakan kuncinya.
William F. Jameson
1
Jawaban yang bagus, meskipun "kira-kira setara" ROFLMAO xD saya akan mengatakannya seperti "agak mirip".
Timo
44

Alasan mengapa Anda tidak dapat memiliki metode statis di antarmuka terletak pada cara Java menyelesaikan referensi statis. Java tidak akan repot mencari instance kelas ketika mencoba untuk mengeksekusi metode statis. Ini karena metode statis tidak tergantung pada instance dan karenanya dapat dieksekusi langsung dari file kelas. Mengingat bahwa semua metode dalam antarmuka adalah abstrak, VM harus mencari implementasi antarmuka tertentu untuk menemukan kode di belakang metode statis sehingga dapat dieksekusi. Ini kemudian bertentangan dengan cara kerja resolusi metode statis dan akan memperkenalkan ketidakkonsistenan ke dalam bahasa.

Espo
sumber
3
Penjelasan ini tidak menjelaskan masalahnya. Setiap antarmuka memiliki file kelas sendiri, itu bisa berisi metode statis. Jadi tidak diperlukan pencarian untuk implementasi tertentu.
Mnementh
Tidak semua jenis antarmuka di Jawa berada di dalam file itu sendiri, juga tidak harus sesuai dengan JLS. Selain itu JLS tidak menetapkan bahwa kelas harus selalu disimpan dengan sistem file, justru sebaliknya.
Vlad Gudim
4
@ Tagophil: Antarmuka tidak boleh dalam satu file java, tetapi itu akan memiliki file kelas sendiri setelah dikompilasi. Itu yang saya tulis.
Mnementh
18

Saya akan menjawab pertanyaan Anda dengan sebuah contoh. Misalkan kita memiliki kelas matematika dengan metode add statis. Anda akan memanggil metode ini seperti ini:

Math.add(2, 3);

Jika Matematika adalah antarmuka dan bukan kelas, itu tidak bisa memiliki fungsi yang ditentukan. Dengan demikian, mengatakan sesuatu seperti Math.add (2, 3) tidak masuk akal.

Kyle Cronin
sumber
11

Alasannya terletak pada prinsip-desain, bahwa java tidak memungkinkan multiple inheritance. Masalah dengan multiple inheritance dapat diilustrasikan dengan contoh berikut:

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

Sekarang apa yang terjadi jika Anda memanggil Cx ()? Apakah Ax () atau Bx () dieksekusi? Setiap bahasa dengan pewarisan berganda harus menyelesaikan masalah ini.

Antarmuka memungkinkan Java beberapa jenis pewarisan berganda terbatas. Untuk menghindari masalah di atas, mereka tidak diperbolehkan memiliki metode. Jika kita melihat masalah yang sama dengan antarmuka dan metode statis:

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

Masalah yang sama di sini, apa yang terjadi jika Anda memanggil Cx ()?

Mnementh
sumber
Ada alasan untuk downvote? Komentar yang menjelaskan akan menyenangkan.
Mnementh
saya bukan downvoter, tetapi bukankah ini juga berlaku untuk metode non-statis?
nawfal
OK, berikut adalah dua kemungkinan yang berbeda. Suatu metode dapat diimplementasikan atau hanya dideklarasikan. Saya mengerti, bahwa metode statis harus diimplementasikan. Dalam makna itu saya menemukan masalah yang disajikan dalam jawaban saya. Jika Anda tidak melakukan itu, Anda mengalami masalah yang dijelaskan Espo - dan saya tidak mengerti karena saya berasumsi metode statis akan diterapkan. Anda juga tidak dapat mendeklarasikan metode abstrak statis untuk alasan ini, coba saja, kompiler akan mengeluh.
Mnementh
Ok, lupakan bagian implementasi. pertanyaannya adalah mengapa tidak bisa kita nyatakan. ya kompiler akan mengeluh dan mengapa itu adalah pertanyaannya. yang saya pikir Anda tidak menjawab.
nawfal
1
Bagaimana situasi di sana menjadi lebih buruk daripada memiliki antarmuka Aberisi int x(int z);dan antarmuka Bmengandung string x(int x);? Apa arti dari x(3)antarmuka C?
supercat
7

Metode statis bukan metode instan. Tidak ada konteks instance, oleh karena itu untuk mengimplementasikannya dari antarmuka tidak masuk akal.

Ryan Farley
sumber
5

Sekarang Java8 memungkinkan kita untuk mendefinisikan bahkan Metode Statis di Antarmuka.

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

Catatan: Metode dalam Antarmuka masih abstrak secara publik jika kita tidak secara eksplisit menggunakan kata kunci default / statis untuk menjadikannya Metode default dan metode Stat resp.

Anandaraja_Srinivasan
sumber
4

Ada jawaban yang sangat bagus dan ringkas untuk pertanyaan Anda di sini . (Itu menurut saya cara yang sangat mudah untuk menjelaskannya sehingga saya ingin menghubungkannya dari sini.)

Zarkonnen
sumber
Ini bukan jawaban untuk pertanyaan, paling baik itu adalah komentar.
CubeJockey
3

Tampaknya metode statis di antarmuka mungkin didukung di Java 8 , well, solusi saya hanya mendefinisikan mereka di kelas dalam.

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

Teknik yang sama juga dapat digunakan dalam anotasi:

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

Kelas dalam harus selalu diakses dalam bentuk Interface.fn...alih-alih Class.fn..., maka, Anda dapat menyingkirkan masalah ambigu.

Xiè Jìléi
sumber
2

Antarmuka digunakan untuk polimorfisme, yang berlaku untuk Objek, bukan tipe. Oleh karena itu (sebagaimana telah dicatat) tidak masuk akal untuk memiliki anggota antarmuka statis.

Rob Cooper
sumber
Dalam beberapa konteks reflektif sepertinya masuk akal
Cruncher
1

Java 8 telah mengubah dunia Anda dapat memiliki metode statis dalam antarmuka tetapi memaksa Anda untuk memberikan implementasi untuk itu.

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

}

Kumar Abhishek
sumber
0

Kombinasi ilegal dari pengubah: statis dan abstrak

Jika anggota kelas dinyatakan sebagai statis, dapat digunakan dengan nama kelasnya yang terbatas pada kelas itu, tanpa membuat objek.

Jika anggota kelas dinyatakan sebagai abstrak, Anda harus mendeklarasikan kelas sebagai abstrak dan Anda harus memberikan implementasi anggota abstrak di kelas yang diwariskan (Sub-Kelas).

Anda perlu memberikan implementasi kepada anggota abstrak kelas di sub-kelas di mana Anda akan mengubah perilaku metode statis, juga dinyatakan sebagai abstrak yang terbatas pada kelas dasar, yang tidak benar

Sankar
sumber
Bagaimana ini menjawab pertanyaan? OP bertanya tentang antarmuka saat Anda menulis tentang kelas.
Lucky
0

Karena metode statis tidak dapat diwarisi. Jadi tidak ada gunanya menempatkannya di antarmuka. Antarmuka pada dasarnya adalah kontrak yang harus diikuti oleh semua pelanggannya. Menempatkan metode statis di antarmuka akan memaksa pelanggan untuk mengimplementasikannya. yang sekarang menjadi bertentangan dengan fakta bahwa metode statis tidak dapat diwarisi.

ip_x
sumber
metode statis selalu diwariskan tetapi mereka tidak dapat diganti.
Akki
0

Dengan Java 8 , antarmuka sekarang dapat memiliki metode statis.

Misalnya, Pembanding memiliki metode naturalOrder () statis.

Persyaratan bahwa antarmuka tidak dapat memiliki implementasi juga telah dilonggarkan. Antarmuka sekarang dapat mendeklarasikan implementasi metode "default", yang seperti implementasi normal dengan satu pengecualian: jika Anda mewarisi implementasi default dari antarmuka dan implementasi normal dari superclass, implementasi superclass akan selalu menjadi prioritas.

Ishara
sumber
OH TUHAN! Kami memiliki programmer yang serius (dan saya, komentator) menjawab (dan saya, berkomentar) pertanyaan berumur 10 tahun.
Mohamed Anees A
Saya tidak melihat tanggal :)
Ishara
Ha ha! Tidak masalah!
Mohamed Anees A
-2

Mungkin contoh kode akan membantu, saya akan menggunakan C #, tetapi Anda harus dapat mengikuti.

Mari kita berpura-pura kita memiliki antarmuka yang disebut IPayable

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

Sekarang, kami memiliki dua kelas konkret yang mengimplementasikan antarmuka ini:

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

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

Sekarang, mari berpura-pura kita memiliki koleksi berbagai akun, untuk melakukan ini kita akan menggunakan daftar generik dari jenis IPayable

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

Sekarang, kami ingin membayar $ 50,00 ke semua akun itu:

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

Jadi sekarang Anda melihat bagaimana antarmuka sangat berguna.

Mereka digunakan hanya pada objek instantiated. Bukan di kelas statis.

Jika Anda melakukan pembayaran statis, saat perulangan melalui akun IPayable di akun ToPay, tidak akan ada cara untuk mengetahui apakah harus membayar panggilan di BusinessAcount atau CustomerAccount.

FlySwat
sumber
Hanya karena metode statis tidak masuk akal dalam contoh INI, tidak berarti mereka tidak masuk akal dalam contoh APAPUN. Dalam contoh Anda jika antarmuka IPayable memiliki metode statis "IncrementPayables" yang melacak berapa banyak hutang ditambahkan, ini akan menjadi kasus penggunaan nyata. Tentu saja, kita selalu bisa menggunakan kelas abstrak, tapi bukan itu yang Anda bicarakan. Contoh Anda sendiri tidak merusak metode statis di antarmuka.
Cruncher