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:
Saya ingin antarmuka IXMLizable memungkinkan saya untuk mengkonversi kelas yang mengimplementasikannya ke elemen XML (menggunakan polimorfisme, berfungsi dengan baik).
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?
sumber
Jawaban:
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:
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?Karena Anda harus secara eksplisit memberi nama tipe konkret
Foo
ketika "membangun" objek baru, kompilator dapat memverifikasi bahwa ia memang memiliki metode pabrik yang diperlukan. Dan jika tidak, lalu bagaimana? Jika saya bisa menerapkanIXMLizable
yang tidak memiliki "konstruktor", dan saya membuat sebuah instance dan menyebarkannya ke kode Anda, itu adalah sebuahIXMLizable
dengan 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.
sumber
RESET()
kelas tertentu? Kamu akan menulisSomeClass.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.T
tanpa mengetahuiT
secara 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.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:
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.
sumber
static
istilah yang payah dalam bahasa, dan sudah terlalu jauh. Jadi memilikinya dengan sendirinya sudah samar. Lihat contoh saya di atas stackoverflow.com/questions/512877/… {shrug}.Biasanya ini dilakukan dengan menggunakan pola Pabrik
sumber
Dengan munculnya Java 8 sekarang dimungkinkan untuk menulis metode standar dan statis di antarmuka. docs.oracle/staticMethod
Sebagai contoh:
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.
sumber
Karena metode statis tidak dapat ditimpa dalam subkelas, dan karenanya mereka tidak bisa abstrak. Dan semua metode dalam sebuah antarmuka yang, de facto , abstrak.
sumber
Sebenarnya Anda bisa di Java 8.
Sesuai dokumen Java :
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:
dari pada
Contoh metode statis (dari dokumen itu sendiri):
sumber
Antarmuka berkaitan dengan polimorfisme yang secara inheren terkait dengan instance objek, bukan kelas. Karenanya statis tidak masuk akal dalam konteks antarmuka.
sumber
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 ...
sumber
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!
sumber
Biarkan saya ulangi pertanyaan itu untuk Anda dengan mengisi definisi.
Atau, lebih lengkapnya, Jika saya ingin memanggil metode tanpa instance, tetapi mengetahui kelas, bagaimana saya bisa menyelesaikannya berdasarkan instance yang tidak saya miliki.
sumber
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:
dan memuat Orang dengan ID yang akan Anda lakukan
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.
sumber
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.
sumber
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.
sumber
Semua metode dalam suatu antarmuka secara eksplisit abstrak dan karenanya Anda tidak dapat mendefinisikannya sebagai statis karena metode statis tidak bisa abstrak.
sumber
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 antarmukaISomething
juga 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
.sumber
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!
sumber
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:
Dalam hal ini yang Anda miliki adalah dua kelas dengan 2 metode statis berbeda yang disebut methodX ().
sumber
Misalkan Anda bisa melakukannya; pertimbangkan contoh ini:
sumber
A.thisIsTheMethod()
akan mencetak "I'm class B".B.thisIsTheMethod()
akan mencetak "Saya kelas B".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
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.sumber
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:
Contoh satu definisi enum:
Definisi utilitas enum umum:
sumber
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.
sumber
Untuk mengatasi ini: error: missing method body, atau mendeklarasikan abstrak static void main (String [] args);
output: 20
Sekarang kita dapat menggunakan metode statis di antarmuka
sumber
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
maka Anda tidak perlu mendeklarasikannya di antarmuka. Jika Anda ingin memanggil mereka suka
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
tidak bergantung pada kenyataan bahwa setiap implementasi antarmuka memiliki metode ini, jadi Anda tidak perlu java untuk membantu Anda memastikannya.
sumber
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.
sumber