Mengapa saya tidak bisa mendefinisikan metode statis di antarmuka Java?


499

EDIT: Pada Java 8, metode statis sekarang diizinkan di antarmuka.

Inilah contohnya:

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

Tentu saja ini tidak akan berhasil. Namun mengapa tidak?

Salah satu masalah yang mungkin terjadi, apa yang terjadi ketika Anda menelepon:

IXMLizable.newInstanceFromXML(e);

Dalam hal ini, saya pikir itu harus memanggil metode kosong (yaitu {}). Semua subclass akan dipaksa untuk mengimplementasikan metode statis, jadi mereka semua akan baik-baik saja ketika memanggil metode statis. Jadi mengapa ini tidak mungkin?

EDIT: Saya kira saya sedang mencari jawaban yang lebih dalam dari "karena memang begitulah Java".

Apakah ada alasan teknologi tertentu mengapa metode statis tidak dapat ditimpa? Yaitu, mengapa para perancang Jawa memutuskan untuk membuat metode instan yang bisa ditimpa tetapi bukan metode statis?

EDIT: Masalah dengan desain saya adalah saya mencoba menggunakan antarmuka untuk menegakkan konvensi pengkodean.

Artinya, tujuan antarmuka ada dua:

  1. Saya ingin antarmuka IXMLizable memungkinkan saya untuk mengkonversi kelas yang mengimplementasikannya ke elemen XML (menggunakan polimorfisme, berfungsi dengan baik).

  2. Jika seseorang ingin membuat instance baru dari kelas yang mengimplementasikan antarmuka IXMLizable, mereka akan selalu tahu bahwa akan ada konstruktor statisInstanceFromXML (Elemen e) baru.

Apakah ada cara lain untuk memastikan ini, selain hanya memberikan komentar di antarmuka?


4
Anda tidak perlu mengacaukan definisi metode (dan bidang) dengan publik di antarmuka, btw.
Tom Hawtin - tackline

Hmm, sepertinya merupakan duplikat dari stackoverflow.com/questions/21817/… . Belum pernah melihat itu sebelumnya.
Michael Myers

1
Bisakah Anda memberikan beberapa kode bagaimana Anda ingin menggunakan metode antarmuka statis?
Pavel Feldman

43
Ini akan dimungkinkan di Java 8: docs.oracle.com/javase/tutorial/java/IandI/…
dakshang

1
@dakshang Ya, tapi itu tidak melakukan apa yang diinginkan OP.
user253751

Jawaban:


518

Java 8 memungkinkan metode antarmuka statis

Dengan Java 8, antarmuka dapat memiliki metode statis. Mereka juga dapat memiliki metode contoh konkret, tetapi tidak bidang contoh.

Sebenarnya ada dua pertanyaan di sini:

  1. Mengapa, di masa lalu yang buruk, antarmuka tidak dapat berisi metode statis?
  2. Mengapa metode statis tidak dapat ditimpa?

Metode statis dalam antarmuka

Tidak ada alasan teknis yang kuat mengapa antarmuka tidak bisa memiliki metode statis di versi sebelumnya. Ini disimpulkan dengan baik oleh poster pertanyaan rangkap. Metode antarmuka statis awalnya dianggap sebagai perubahan bahasa kecil, dan kemudian ada proposal resmi untuk menambahkannya di Java 7, tetapi kemudian dibatalkan karena komplikasi yang tidak terduga.

Akhirnya, Java 8 memperkenalkan metode antarmuka statis, serta metode instan yang dapat dikesampingkan dengan implementasi default. Mereka masih tidak dapat memiliki bidang contoh. Fitur-fitur ini adalah bagian dari dukungan ekspresi lambda, dan Anda dapat membaca lebih banyak tentang mereka di Bagian H JSR 335.

Mengganti metode statis

Jawaban untuk pertanyaan kedua sedikit lebih rumit.

Metode statis dapat diselesaikan pada waktu kompilasi. Pengiriman dinamis masuk akal untuk metode contoh, di mana kompiler tidak dapat menentukan jenis objek konkret, dan, dengan demikian, tidak dapat menyelesaikan metode untuk memanggil. Tetapi menggunakan metode statis memerlukan kelas, dan karena kelas itu dikenal secara statis — pada waktu kompilasi — pengiriman dinamis tidak diperlukan.

Sedikit latar belakang tentang cara kerja metode contoh diperlukan untuk memahami apa yang terjadi di sini. Saya yakin implementasi sebenarnya sangat berbeda, tetapi izinkan saya menjelaskan gagasan saya tentang metode pengiriman, yang modelnya mengamati perilaku secara akurat.

Berpura-pura bahwa setiap kelas memiliki tabel hash yang memetakan tanda tangan metode (nama dan tipe parameter) ke potongan kode yang sebenarnya untuk mengimplementasikan metode. Ketika mesin virtual mencoba untuk memanggil metode pada contoh, itu meminta objek untuk kelasnya dan mencari tanda tangan yang diminta di tabel kelas. Jika badan metode ditemukan, itu dipanggil. Jika tidak, kelas induk dari kelas tersebut diperoleh, dan pencarian diulangi di sana. Ini berlanjut sampai metode ditemukan, atau tidak ada lagi kelas induk — yang menghasilkan a NoSuchMethodError.

Jika superclass dan subclass keduanya memiliki entri di tabel mereka untuk tanda tangan metode yang sama, versi sub-kelas ditemui terlebih dahulu, dan versi superclass tidak pernah digunakan — ini adalah "override".

Sekarang, misalkan kita melewatkan instance objek dan mulai dengan subkelas. Resolusi dapat dilanjutkan seperti di atas, memberi Anda semacam metode statis "yang dapat ditimpa". Resolusi semua dapat terjadi pada waktu kompilasi, karena kompiler mulai dari kelas yang dikenal, daripada menunggu sampai runtime untuk meminta objek dari tipe yang tidak ditentukan untuk kelasnya. Tidak ada gunanya "mengganti" metode statis karena kita selalu dapat menentukan kelas yang berisi versi yang diinginkan.


Konstruktor "antarmuka"

Ini sedikit lebih banyak bahan untuk membahas suntingan terbaru untuk pertanyaan itu.

Sepertinya Anda ingin secara efektif mengamanatkan metode seperti konstruktor untuk setiap implementasi IXMLizable. Lupakan tentang mencoba menegakkan ini dengan antarmuka sebentar, dan berpura-pura bahwa Anda memiliki beberapa kelas yang memenuhi persyaratan ini. Bagaimana Anda menggunakannya?

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

Foo obj = Foo.newInstanceFromXML(e);

Karena Anda harus secara eksplisit memberi nama tipe konkret Fooketika "membangun" objek baru, kompilator dapat memverifikasi bahwa ia memang memiliki metode pabrik yang diperlukan. Dan jika tidak, lalu bagaimana? Jika saya bisa menerapkan IXMLizableyang tidak memiliki "konstruktor", dan saya membuat sebuah instance dan menyebarkannya ke kode Anda, itu adalah sebuah IXMLizabledengan semua antarmuka yang diperlukan.

Konstruksi adalah bagian dari implementasi, bukan antarmuka. Kode apa pun yang berhasil bekerja dengan antarmuka tidak peduli tentang konstruktor. Kode apa pun yang peduli tentang konstruktor perlu mengetahui tipe konkretnya, dan antarmuka dapat diabaikan.



12
Mungkinkah alasan # 1 menjadi banyak warisan? Karena kita dapat mewarisi dari banyak antarmuka, jika dua antarmuka mengandung tanda tangan metode statis yang sama dan kemudian sebuah kelas mengimplementasikan keduanya dan memanggil metode itu, maka hal-hal bisa menjadi rumit dengan cara yang ingin dihindari oleh pembuat bahasa Jawa dengan melarang pewarisan banyak kelas di posisi pertama. Argumen yang sama jelas dapat dibuat untuk antarmuka yang tidak mengizinkan definisi metode apa pun di dalamnya.
shrini1000

1
@ shrini1000 - Tidak, metode statis diselesaikan pada waktu kompilasi. Ambiguitas dapat ditangani dengan cara yang sama seperti itu ditangani dengan konstanta: dengan kesalahan kompiler. Namun, proposal di bawah Project Coin ditolak, mengutip beberapa kesulitan yang tidak terduga. Tidak yakin apa itu, tapi saya tidak berpikir itu sesuai dengan ini.
erickson

1
@ tgm1024 Ya, bagian "Konstruktor 'antarmuka'" menjelaskan mengapa tidak masuk akal untuk mencoba memunculkan perilaku polimorfik melalui jenis yang dikenal pada waktu kompilasi. Bagaimana Anda memohon RESET()kelas tertentu? Kamu akan menulis SomeClass.RESET(). Jadi Anda tidak perlu antarmuka untuk menggambarkan API itu; itu statis. Antarmuka digunakan ketika Anda tidak tahu jenis konkret pada waktu kompilasi. Itu tidak pernah terjadi dengan metode statis.
erickson

2
"Konstruksi adalah bagian dari implementasi, bukan antarmuka. Kode apa pun yang berhasil bekerja dengan antarmuka tidak peduli dengan konstruktor." - Itu jelas tidak benar. Dalam bahasa lain (misalnya Swift), saya dapat membuat instance baru Ttanpa mengetahui Tsecara statis, karena saya berjanji dalam antarmuka bahwa konstruktor tertentu (atau metode statis) akan ada saat runtime. Fakta bahwa generasi tidak mungkin ditentukan di Jawa tidak berarti itu bukan hal yang berarti untuk dilakukan.
Raphael

48

Ini sudah ditanyakan dan dijawab, di sini

Untuk menggandakan jawaban saya:

Tidak pernah ada titik untuk mendeklarasikan metode statis dalam suatu antarmuka. Mereka tidak dapat dieksekusi oleh panggilan normal MyInterface.staticMethod (). Jika Anda memanggil mereka dengan menentukan kelas implementasi MyImplementor.staticMethod () maka Anda harus tahu kelas yang sebenarnya, sehingga tidak relevan apakah antarmuka mengandungnya atau tidak.

Lebih penting lagi, metode statis tidak pernah diganti, dan jika Anda mencoba melakukannya:

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

aturan untuk static mengatakan bahwa metode yang didefinisikan dalam tipe var yang dideklarasikan harus dieksekusi. Karena ini adalah antarmuka, ini tidak mungkin.

Alasan Anda tidak dapat menjalankan "result = MyInterface.staticMethod ()" adalah karena ia harus menjalankan versi metode yang didefinisikan dalam MyInterface. Tetapi tidak mungkin ada versi yang didefinisikan di MyInterface, karena ini adalah antarmuka. Itu tidak memiliki kode menurut definisi.

Meskipun Anda dapat mengatakan bahwa ini berarti "karena Java melakukannya dengan cara seperti itu", pada kenyataannya keputusan tersebut merupakan konsekuensi logis dari keputusan desain lainnya, juga dibuat untuk alasan yang sangat bagus.


14
Jika Anda menggunakan <T extends MyInterface> sebagai parameter tipe generik, alangkah baiknya untuk menjamin melalui antarmuka bahwa T dapat .doSomething ().
Chris Betti

4
Sementara saya mengerti argumennya, saya setuju dengan @Chris_Betti (bahkan untuk tipe non-generik): akan lebih baik jika struktur kode memastikan bahwa beberapa kelas mengimplementasikan API statis tertentu. Mungkin dimungkinkan menggunakan konsep yang berbeda ...
Juh_

@ Juh_, ..... atau kata kunci baru jika benar-benar diperlukan. Saya percaya staticistilah yang payah dalam bahasa, dan sudah terlalu jauh. Jadi memilikinya dengan sendirinya sudah samar. Lihat contoh saya di atas stackoverflow.com/questions/512877/… {shrug}.

3
Ini tampaknya tidak benar: "Tidak pernah ada titik untuk mendeklarasikan metode statis di antarmuka." Jika saya memiliki kumpulan kelas yang, tanpa instantiated, dapat menawarkan saya beberapa informasi tetapi saya membutuhkan antarmuka umum untuk memasukkan informasi tingkat kelas statis ini (yaitu antarmuka dengan metode statis yang dapat ditimpa) maka itu penggunaan yang valid . Pikirkan refleksi ++, di mana Anda dapat menangkap meta-informasi tentang properti kelas tanpa merambah dengan atribut, refleksi, dll.
Jason

1
"Tidak pernah ada titik untuk mendeklarasikan metode statis dalam sebuah antarmuka." Ini tidak benar: bayangkan sistem Anda memiliki penyelesai kelas default. Jika mendeteksi bahwa Anda menerapkan metode ContainerInjectionInterce :: create (Container $ container), maka itu akan membuat objek dengan fungsi ini misalnya.
user3790897

37

Biasanya ini dilakukan dengan menggunakan pola Pabrik

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

public interface IXMLizable {
  public Element toXMLElement();
}

7
Memberi +1 pada pola pabrik terdengar seperti solusi untuk masalah tersebut. (meskipun tidak dengan pertanyaan)
pvgoddijn

Dapatkah seseorang memberi tahu saya apa arti dari menempatkan <T extends IXMLizable> di sini. Saya baru di java. Apa fungsinya?
Nuwan Harshakumara Piyarathna

1
@NuwanHarshakumaraPiyarathna T harus berupa kelas yang memperpanjang IXMLizable. Lihatlah ke generik Jawa untuk pemahaman yang lebih baik tentang apa artinya ini
adrian

37

Dengan munculnya Java 8 sekarang dimungkinkan untuk menulis metode standar dan statis di antarmuka. docs.oracle/staticMethod

Sebagai contoh:

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

Hasil : 6

TIP: Memanggil metode antarmuka statis tidak perlu diimplementasikan oleh kelas mana pun. Tentunya, ini terjadi karena aturan yang sama untuk metode statis dalam superclasses berlaku untuk metode statis pada antarmuka.


Ini adalah contoh sempurna dari pertanyaan ini.

21

Karena metode statis tidak dapat ditimpa dalam subkelas, dan karenanya mereka tidak bisa abstrak. Dan semua metode dalam sebuah antarmuka yang, de facto , abstrak.


2
Anda selalu dapat memaksa setiap jenis untuk menerapkan metode antarmuka statis apa pun. Kacamata ketik, siapa saja?
MichaelGG

16
Langkah di luar diri Anda dan jawab pertanyaan: Mengapa metode statis tidak bisa ditimpa? Jika metode statis dapat diganti, seperti apa bentuknya? Apa yang bisa kamu lakukan dengan mereka? Jawaban ini pada dasarnya adalah "Kamu tidak bisa karena kamu tidak bisa."
erickson

10

Mengapa saya tidak bisa mendefinisikan metode statis di antarmuka Java?

Sebenarnya Anda bisa di Java 8.

Sesuai dokumen Java :

Metode statis adalah metode yang dikaitkan dengan kelas di mana ia didefinisikan daripada dengan objek apa pun. Setiap instance kelas membagikan metode statisnya

Di Java 8 sebuah antarmuka dapat memiliki metode default dan metode statis . Ini membuatnya lebih mudah bagi kami untuk mengatur metode pembantu di perpustakaan kami. Kita dapat menyimpan metode statis khusus untuk antarmuka di antarmuka yang sama daripada di kelas yang terpisah.

Contoh metode default:

list.sort(ordering);

dari pada

Collections.sort(list, ordering);

Contoh metode statis (dari dokumen itu sendiri):

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

Antarmuka berkaitan dengan polimorfisme yang secara inheren terkait dengan instance objek, bukan kelas. Karenanya statis tidak masuk akal dalam konteks antarmuka.


Logika yang jelas dan ringkas. Baik.
Oke Uwechue

6

Pertama, semua keputusan bahasa adalah keputusan yang dibuat oleh pembuat bahasa. Tidak ada apa pun di dunia rekayasa perangkat lunak atau penulisan bahasa atau penulisan kompiler / juru bahasa yang mengatakan bahwa metode statis tidak dapat menjadi bagian dari antarmuka. Saya telah membuat beberapa bahasa dan kompiler tertulis untuk mereka - itu semua hanya duduk dan mendefinisikan semantik yang bermakna. Saya berpendapat bahwa semantik dari metode statis dalam sebuah antarmuka sangat jelas - bahkan jika kompiler harus menunda resolusi metode untuk menjalankan-waktu.

Kedua, bahwa kita menggunakan metode statis sama sekali berarti ada alasan yang sah untuk memiliki pola antarmuka yang mencakup metode statis - saya tidak dapat berbicara untuk Anda, tetapi saya menggunakan metode statis secara teratur.

Jawaban yang benar kemungkinan besar adalah bahwa tidak ada kebutuhan yang dirasakan, pada saat bahasa itu didefinisikan, untuk metode statis di antarmuka. Jawa telah tumbuh banyak selama bertahun-tahun dan ini adalah item yang tampaknya telah menarik perhatian. Bahwa itu dilihat untuk Java 7 menunjukkan bahwa itu naik ke tingkat minat yang mungkin mengakibatkan perubahan bahasa. Saya, untuk satu, akan senang ketika saya tidak lagi harus instantiate objek hanya supaya saya bisa memanggil metode pengambil non-statis untuk mengakses variabel statis dalam contoh subclass ...


5

Metode statis tidak virtual seperti metode contoh jadi saya kira desainer Java memutuskan mereka tidak ingin mereka dalam antarmuka.

Tetapi Anda dapat menempatkan kelas yang berisi metode statis di dalam antarmuka. Anda bisa mencobanya!

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

5
  • "Apakah ada alasan tertentu bahwa metode statis tidak dapat diganti".

Biarkan saya ulangi pertanyaan itu untuk Anda dengan mengisi definisi.

  • "Apakah ada alasan tertentu bahwa metode yang diselesaikan pada waktu kompilasi tidak dapat diselesaikan pada saat runtime."

Atau, lebih lengkapnya, Jika saya ingin memanggil metode tanpa instance, tetapi mengetahui kelas, bagaimana saya bisa menyelesaikannya berdasarkan instance yang tidak saya miliki.


3

Beberapa jawaban telah membahas masalah dengan konsep metode statis yang dapat ditimpa. Namun terkadang Anda menemukan sebuah pola di mana sepertinya itulah yang ingin Anda gunakan.

Sebagai contoh, saya bekerja dengan lapisan objek-relasional yang memiliki objek nilai, tetapi juga memiliki perintah untuk memanipulasi objek nilai. Untuk berbagai alasan, setiap kelas objek nilai harus mendefinisikan beberapa metode statis yang memungkinkan kerangka kerja menemukan perintah instance. Misalnya, untuk membuat Orang yang akan Anda lakukan:

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

dan memuat Orang dengan ID yang akan Anda lakukan

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

Ini cukup nyaman, namun memiliki masalah; khususnya keberadaan metode statis tidak dapat ditegakkan di antarmuka. Metode statis yang dapat ditimpa dalam antarmuka akan persis apa yang kita butuhkan, jika saja itu bisa bekerja entah bagaimana.

EJB menyelesaikan masalah ini dengan memiliki antarmuka Home; setiap objek tahu bagaimana menemukan Rumah dan Rumah berisi metode "statis". Dengan cara ini metode "statis" dapat diganti sesuai kebutuhan, dan Anda tidak mengacaukan antarmuka normal (disebut "Remote") dengan metode yang tidak berlaku untuk instance kacang Anda. Buat saja antarmuka normal tentukan metode "getHome ()". Kembalikan instance dari objek Home (yang bisa saja singleton, saya kira) dan penelepon dapat melakukan operasi yang mempengaruhi semua objek Person.


3

Mengomentari EDIT: As of Java 8, static methods are now allowed in interfaces.

Benar, metode statis karena Java 8 diizinkan di antarmuka, tetapi contoh Anda masih tidak akan berfungsi. Anda tidak bisa hanya mendefinisikan metode statis: Anda harus mengimplementasikannya atau Anda akan mendapatkan kesalahan kompilasi.


2

Nah, tanpa generik, antarmuka statis tidak berguna karena semua panggilan metode statis diselesaikan pada waktu kompilasi. Jadi, tidak ada gunanya bagi mereka.

Dengan obat generik, mereka telah digunakan - dengan atau tanpa implementasi standar. Tentunya akan perlu mengesampingkan dan sebagainya. Namun, dugaan saya adalah bahwa penggunaan seperti itu tidak terlalu OO (seperti jawaban lain tunjukkan dengan enteng) dan karenanya tidak dianggap sepadan dengan upaya yang mereka perlukan untuk mengimplementasikannya dengan bermanfaat.


1
Apa hubungannya obat generik dengan ini? Metode statis pada antarmuka masih tidak dapat dieksekusi.
DJClayworth

Pertama, itu akan menjadi keputusan implementasi. Tapi saya kira dia tidak ingin memanggil metode statis pada antarmuka (dia hanya bisa menggunakan kelas). Tetapi sebaliknya ingin memiliki sesuatu yang agak seperti typeclass atau yang lainnya dari parameter type. Bahkan, hasil edit terbarunya menunjukkan ini dengan lebih jelas.
MichaelGG

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

Semua metode dalam suatu antarmuka secara eksplisit abstrak dan karenanya Anda tidak dapat mendefinisikannya sebagai statis karena metode statis tidak bisa abstrak.


1

Sebuah antarmuka tidak pernah bisa dereferenced statis, misalnya ISomething.member. Antarmuka selalu direferensikan melalui variabel yang mengacu pada turunan dari subkelas antarmuka. Dengan demikian, referensi antarmuka tidak akan pernah tahu subclass mana yang dirujuk tanpa turunannya dari subclassnya.

Dengan demikian perkiraan terdekat dengan metode statis dalam suatu antarmuka akan menjadi metode non-statis yang mengabaikan "ini", yaitu tidak mengakses anggota non-statis dari instance. Pada abstraksi tingkat rendah, setiap metode non-statis (setelah pencarian dalam tabel apa pun) benar-benar hanya sebuah fungsi dengan ruang lingkup kelas yang menggunakan "ini" sebagai parameter formal implisit. Lihat objek tunggal Scala dan interoperabilitas dengan Java sebagai bukti konsep itu. Dan dengan demikian setiap metode statis adalah fungsi dengan ruang lingkup kelas yang tidak mengambil parameter "ini". Jadi biasanya metode statis dapat disebut statis, tetapi seperti yang dinyatakan sebelumnya, sebuah antarmuka tidak memiliki implementasi (abstrak).

Jadi untuk mendapatkan pendekatan terdekat dengan metode statis dalam sebuah antarmuka, adalah dengan menggunakan metode non-statis, maka jangan mengakses anggota instance non-statis. Tidak akan ada manfaat kinerja yang memungkinkan dengan cara lain, karena tidak ada cara untuk menghubungkan secara statis (pada waktu kompilasi) a ISomething.member(). Satu-satunya manfaat yang saya lihat dari metode statis dalam sebuah antarmuka adalah tidak akan memasukkan (yaitu mengabaikan) "implisit" ini dan dengan demikian melarang akses ke salah satu anggota instance non-statis. Ini akan menyatakan secara implisit bahwa fungsi yang tidak mengakses "ini", tidak berubah dan bahkan tidak hanya dibaca sehubungan dengan kelasnya yang berisi. Tetapi deklarasi "statis" dalam sebuah antarmuka ISomethingjuga akan membingungkan orang yang mencoba mengaksesnyaISomething.member()yang akan menyebabkan kesalahan kompilator. Saya kira jika kesalahan kompiler cukup jelas, akan lebih baik daripada mencoba mendidik orang tentang menggunakan metode non-statis untuk mencapai apa yang mereka inginkan (tampaknya sebagian besar metode pabrik), seperti yang kita lakukan di sini (dan telah diulang selama 3 Tanya jawab kali di situs ini), jadi ini jelas merupakan masalah yang tidak intuitif bagi banyak orang. Saya harus memikirkannya sebentar untuk mendapatkan pemahaman yang benar.

Cara untuk mendapatkan bidang statis yang dapat berubah dalam suatu antarmuka adalah menggunakan metode pengambil dan penyetel non-statis dalam suatu antarmuka, untuk mengakses bidang statis itu di dalam subkelas. Sidenote, statika yang tampaknya tidak dapat diubah dapat dideklarasikan dengan antarmuka Java static final.


0

Antarmuka hanya menyediakan daftar hal-hal yang akan disediakan oleh kelas, bukan implementasi aktual dari hal-hal itu, yang merupakan item statis Anda.

Jika Anda ingin statika, gunakan kelas abstrak dan turunkan, jika tidak, hapus statis.

Semoga itu bisa membantu!


2
Nah, secara teori, Anda bisa mendefinisikan antarmuka untuk menyertakan perilaku statis, yaitu, "implementasi antarmuka ini akan memiliki metode statis foo () dengan tanda tangan ini", dan biarkan implementasinya ke kelas tertentu. Saya telah menemukan situasi di mana perilaku ini akan berguna.
Rob

0

Anda tidak dapat mendefinisikan metode statis di antarmuka karena metode statis milik kelas bukan turunan kelas, dan antarmuka bukan Kelas. Baca lebih lanjut di sini.

Namun, jika mau, Anda bisa melakukan ini:

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

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

Dalam hal ini yang Anda miliki adalah dua kelas dengan 2 metode statis berbeda yang disebut methodX ().


0

Misalkan Anda bisa melakukannya; pertimbangkan contoh ini:

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
Itu akan mencetak "Saya kelas A". Namun, jika Anda mengetiknya A.thisIsTheMethod()akan mencetak "I'm class B".
cdmckay

tetapi oyr memanggil metode pada antarmuka bagaimana Anda (atau kompiler) tahu metode mana yang harus dipanggil? (Rember akan ada lebih banyak kelas menerapkan draf Iface
pvgoddijn

maaf, saya bermaksud mengatakan: Namun, jika Anda mengetiknya B.thisIsTheMethod()akan mencetak "Saya kelas B".
cdmckay

saya katakan IFace.ini adalah metode sengaja karena di situlah masalahnya. tidak akan mungkin untuk menyebutnya di antarmuka tanpa perilaku yang tidak terdefinisi (meskipun dideklarasikan di atasnya)
pvgoddijn

0

Sesuatu yang bisa diimplementasikan adalah antarmuka statis (bukan metode statis dalam antarmuka). Semua kelas yang menerapkan antarmuka statis yang diberikan harus menerapkan metode statis yang sesuai. Anda bisa mendapatkan antarmuka SI statis dari Kelas apa pun menggunakan

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

maka kamu bisa menelepon si.method(params). Ini akan berguna (untuk pola desain pabrik misalnya) karena Anda bisa mendapatkan (atau memeriksa implementasi) implementasi metode statis SI dari kelas waktu kompilasi yang tidak diketahui! Pengiriman dinamis diperlukan dan Anda dapat mengganti metode statis (jika bukan final) kelas dengan memperluasnya (ketika dipanggil melalui antarmuka statis). Jelas, metode ini hanya dapat mengakses variabel statis kelas mereka.


0

Sementara saya menyadari bahwa Java 8 menyelesaikan masalah ini, saya pikir saya akan berpadu dengan skenario yang sedang saya kerjakan (dikunci menggunakan Java 7) di mana bisa menentukan metode statis dalam antarmuka akan sangat membantu.

Saya memiliki beberapa definisi enum di mana saya mendefinisikan bidang "id" dan "displayName" bersama dengan metode pembantu mengevaluasi nilai-nilai karena berbagai alasan. Menerapkan antarmuka memungkinkan saya untuk memastikan bahwa metode pengambil ada di tempat tetapi bukan metode pembantu statis. Menjadi enum, benar-benar tidak ada cara yang bersih untuk menurunkan metode pembantu ke dalam kelas abstrak yang diwariskan atau semacamnya sehingga metode harus didefinisikan dalam enum itu sendiri. Juga karena ini adalah enum, Anda tidak akan pernah bisa benar-benar melewatinya sebagai objek instances dan memperlakukannya sebagai jenis antarmuka, tetapi mampu memerlukan keberadaan metode pembantu statis melalui antarmuka adalah apa yang saya sukai itu didukung di Java 8.

Berikut kode yang mengilustrasikan poin saya.

Definisi antarmuka:

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

Contoh satu definisi enum:

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

Definisi utilitas enum umum:

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

Mari kita anggap metode statis diizinkan di antarmuka: * Mereka akan memaksa semua kelas pelaksana untuk mendeklarasikan metode itu. * Antarmuka biasanya akan digunakan melalui objek, jadi satu-satunya metode yang efektif pada mereka adalah yang non-statis. * Setiap kelas yang mengetahui antarmuka tertentu dapat menggunakan metode statisnya. Oleh karena itu metode statis kelas mengimplementasikan akan disebut di bawahnya, tetapi kelas invoker tidak tahu yang mana. Bagaimana mengetahuinya? Tidak ada contoh untuk menebak itu!

Antarmuka dianggap digunakan saat bekerja dengan objek. Dengan cara ini, sebuah objek dibuat dari kelas tertentu, jadi hal terakhir ini terpecahkan. Kelas pemohon tidak perlu tahu kelas tertentu karena instantiasi dapat dilakukan oleh kelas ketiga. Jadi kelas yang memohon hanya tahu antarmuka.

Jika kita ingin ini diperluas ke metode statis, kita harus memiliki kemungkinan untuk menentukan kelas pelaksana sebelumnya, kemudian meneruskan referensi ke kelas pemohon. Ini bisa menggunakan kelas melalui metode statis di antarmuka. Tetapi apa perbedaan antara referensi ini dan objek? Kita hanya perlu objek yang mewakili kelasnya. Sekarang, objek tersebut mewakili kelas lama, dan dapat mengimplementasikan antarmuka baru termasuk metode statis lama - yang sekarang non-statis.

Metaclasses melayani untuk tujuan ini. Anda dapat mencoba kelas Class of Java. Tetapi masalahnya adalah bahwa Java tidak cukup fleksibel untuk ini. Anda tidak dapat mendeklarasikan metode di objek kelas antarmuka.

Ini adalah masalah meta - ketika Anda perlu melakukan keledai

..blah blah

Lagi pula Anda memiliki solusi yang mudah - membuat metode ini tidak statis dengan logika yang sama. Tetapi kemudian Anda harus terlebih dahulu membuat objek untuk memanggil metode.


0

Untuk mengatasi ini: error: missing method body, atau mendeklarasikan abstrak static void main (String [] args);

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

}

output: 20

Sekarang kita dapat menggunakan metode statis di antarmuka


1
Tapi itu tidak berguna. Mendefinisikan metode statis pada antarmuka tidak memaksakan definisi lebih lanjut di kelas yang mengimplementasikan antarmuka tersebut. Jika Anda hanya menghapus metode statis sama sekali dari antarmuka I, kode Anda akan dikompilasi dan tetap berjalan tanpa masalah. Dengan kata lain, Anda TIDAK override metode utama saya antarmuka di kelas InterDemo, hanya menciptakan metode baru dengan tanda tangan yang sama.
Fran Marzoa

-2

Saya pikir java tidak memiliki metode antarmuka statis karena Anda tidak memerlukannya. Anda mungkin berpikir demikian, tetapi ... Bagaimana Anda menggunakannya? Jika Anda ingin memanggil mereka suka

MyImplClass.myMethod()

maka Anda tidak perlu mendeklarasikannya di antarmuka. Jika Anda ingin memanggil mereka suka

myInstance.myMethod()

maka seharusnya tidak statis. Jika Anda benar-benar akan menggunakan cara pertama, tetapi hanya ingin memaksakan setiap implementasi memiliki metode statis, maka itu benar-benar sebuah konvensi pengkodean, bukan kontrak antara instance yang mengimplementasikan antarmuka dan kode panggilan.

Antarmuka memungkinkan Anda untuk menentukan kontrak antara instance kelas yang mengimplementasikan antarmuka dan kode panggilan. Dan java membantu Anda untuk memastikan bahwa kontrak ini tidak dilanggar, sehingga Anda dapat mengandalkannya dan jangan khawatir kelas apa yang mengimplementasikan kontrak ini, cukup "seseorang yang menandatangani kontrak" sudah cukup. Dalam hal antarmuka statis kode Anda

MyImplClass.myMethod()

tidak bergantung pada kenyataan bahwa setiap implementasi antarmuka memiliki metode ini, jadi Anda tidak perlu java untuk membantu Anda memastikannya.


-5

Apa perlunya metode statis dalam antarmuka, metode statis digunakan pada dasarnya ketika Anda tidak harus membuat turunan objek seluruh gagasan antarmuka adalah untuk membawa konsep OOP dengan pengenalan metode statis yang Anda alihkan dari konsep.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.