Saya tahu itu tidak mungkin untuk mendefinisikan konstruktor dalam sebuah antarmuka. Tapi saya bertanya-tanya mengapa, karena saya pikir itu bisa sangat berguna.
Jadi Anda bisa yakin bahwa beberapa bidang dalam kelas didefinisikan untuk setiap implementasi antarmuka ini.
Sebagai contoh, pertimbangkan kelas pesan berikut:
public class MyMessage {
public MyMessage(String receiver) {
this.receiver = receiver;
}
private String receiver;
public void send() {
//some implementation for sending the mssage to the receiver
}
}
Jika sebuah mendefinisikan antarmuka untuk kelas ini sehingga saya dapat memiliki lebih banyak kelas yang mengimplementasikan antarmuka pesan, saya hanya dapat mendefinisikan metode kirim dan bukan konstruktor. Jadi bagaimana saya bisa memastikan bahwa setiap implementasi kelas ini benar-benar memiliki set penerima? Jika saya menggunakan metode seperti setReceiver(String receiver)
saya tidak dapat memastikan bahwa metode ini benar-benar dipanggil. Di konstruktor saya bisa memastikannya.
Jawaban:
Mengambil beberapa hal yang telah Anda uraikan:
... persyaratan ini persis untuk apa kelas abstrak .
sumber
Message
antarmuka yang mendefinisikansend()
metode, dan jika Sebi ingin memberikan kelas "basis" untuk implementasiMessage
antarmuka, maka sediakanAbstractMessage
juga. Kelas abstrak tidak boleh menggantikan antarmuka, tidak pernah berusaha menyarankannya.Masalah yang Anda dapatkan saat Anda mengizinkan konstruktor di antarmuka berasal dari kemungkinan untuk mengimplementasikan beberapa antarmuka secara bersamaan. Ketika sebuah kelas mengimplementasikan beberapa antarmuka yang mendefinisikan konstruktor yang berbeda, kelas harus mengimplementasikan beberapa konstruktor, masing-masing hanya memuaskan satu antarmuka, tetapi tidak yang lain. Tidak mungkin untuk membangun objek yang memanggil masing-masing konstruktor ini.
Atau dalam kode:
sumber
class A implements Named, HashList { A(){HashList(new list()); Named("name");} }
new Set<Fnord>()
dapat diartikan sebagai "Beri saya sesuatu yang dapat saya gunakan sebagaiSet<Fnord>
"; jika penulisSet<T>
dimaksudkanHashSet<T>
untuk menjadi pelaksana implementasi untuk hal-hal yang tidak memiliki kebutuhan khusus untuk hal lain, antarmuka kemudiannew Set<Fnord>()
dapat didefinisikan dapat dianggap identik dengannew HashSet<Fnord>()
. Untuk kelas untuk mengimplementasikan beberapa antarmuka tidak akan menimbulkan masalah, karenanew InterfaceName()
hanya akan membangun kelas yang ditunjuk oleh antarmuka .A(String,List)
konstruktor Anda bisa menjadi konstruktor yang ditunjuk, danA(String)
danA(List)
bisa juga yang sekunder yang menyebutnya. Kode Anda bukan contoh balasan, hanya kode yang buruk.Antarmuka mendefinisikan kontrak untuk API, yaitu seperangkat metode yang disetujui oleh pelaksana dan pengguna API. Antarmuka tidak memiliki implementasi instances, karenanya tidak ada konstruktor.
Kasus penggunaan yang Anda gambarkan mirip dengan kelas abstrak di mana konstruktor memanggil metode metode abstrak yang diimplementasikan dalam kelas anak.
Masalah yang melekat di sini adalah bahwa sementara konstruktor dasar sedang dieksekusi, objek anak belum dibangun, dan karenanya dalam keadaan yang tidak dapat diprediksi.
Untuk meringkas: apakah itu meminta masalah ketika Anda memanggil metode kelebihan beban dari konstruktor induk, untuk mengutip mindprod :
sumber
Pekerjaan di sekitar yang dapat Anda coba adalah mendefinisikan a
getInstance()
metode di antarmuka Anda sehingga pelaksana menyadari parameter apa yang perlu ditangani. Ini tidak sekokoh kelas abstrak, tetapi memungkinkan lebih banyak fleksibilitas sebagai antarmuka.Namun solusi ini memang mengharuskan Anda untuk menggunakan
getInstance()
instantiate semua objek dari antarmuka ini.Misalnya
sumber
Hanya ada bidang statis dalam antarmuka yang tidak perlu diinisialisasi selama pembuatan objek di subkelas dan metode antarmuka harus menyediakan implementasi aktual dalam subkelas. Jadi tidak perlu konstruktor dalam antarmuka.
Alasan kedua - selama pembuatan objek subclass, induk konstruktor dipanggil. Tetapi jika akan ada lebih dari satu antarmuka diimplementasikan maka konflik akan terjadi selama panggilan konstruktor antarmuka untuk mana konstruktor antarmuka akan memanggil pertama
sumber
Jika Anda ingin memastikan bahwa setiap implementasi antarmuka berisi bidang tertentu, Anda hanya perlu menambahkan antarmuka pengambil untuk bidang itu :
Receiver
objek tersebut harus diteruskan ke kelas dalam beberapa cara (baik dengan konstruktor atau oleh setter)sumber
Ketergantungan yang tidak dirujuk dalam metode antarmuka harus dianggap sebagai detail implementasi, bukan sesuatu yang ditegakkan antarmuka. Tentu saja ada pengecualian, tetapi sebagai aturan, Anda harus mendefinisikan antarmuka Anda seperti apa perilaku yang diharapkan. Keadaan internal dari implementasi yang diberikan tidak boleh menjadi masalah desain antarmuka.
sumber
Lihat pertanyaan ini untuk alasannya (diambil dari komentar).
Jika Anda benar-benar perlu melakukan sesuatu seperti ini, Anda mungkin menginginkan kelas dasar abstrak daripada antarmuka.
sumber
Ini karena antarmuka tidak memungkinkan untuk mendefinisikan tubuh metode di dalamnya. Tetapi kita harus mendefinisikan konstruktor di kelas yang sama dengan antarmuka memiliki pengubah abstrak default untuk semua metode untuk mendefinisikan. Itu sebabnya kami tidak dapat mendefinisikan konstruktor di antarmuka.
sumber
Inilah contoh menggunakan Teknik ini. Dalam contoh spesifik ini, kode membuat panggilan ke Firebase menggunakan tiruan
MyCompletionListener
yang merupakan antarmuka yang ditutupi sebagai kelas abstrak, antarmuka dengan konstruktorsumber
private
pengubah aksesinterface
?Umumnya konstruktor adalah untuk menginisialisasi anggota non-statis dari kelas tertentu sehubungan dengan objek.
Tidak ada pembuatan objek untuk antarmuka karena hanya ada metode yang dideklarasikan tetapi tidak didefinisikan metode. Mengapa kita tidak dapat membuat objek ke metode yang dideklarasikan adalah pembuatan objek tidak lain adalah mengalokasikan sebagian memori (dalam memori tumpukan) untuk anggota non-statis.
JVM akan membuat memori untuk anggota yang sepenuhnya dikembangkan dan siap untuk digunakan. Berdasarkan anggota tersebut, JVM menghitung berapa banyak memori yang diperlukan untuk mereka dan menciptakan memori.
Jika metode yang dideklarasikan, JVM tidak dapat menghitung berapa banyak memori yang diperlukan untuk metode yang dinyatakan ini karena implementasinya di masa depan yang tidak dilakukan saat ini. jadi pembuatan objek tidak dimungkinkan untuk antarmuka.
kesimpulan:
tanpa penciptaan objek, tidak ada kesempatan untuk menginisialisasi anggota non-statis melalui konstruktor. Itulah sebabnya konstruktor tidak diperbolehkan di dalam antarmuka. (karena tidak ada penggunaan konstruktor di dalam antarmuka)
sumber