Java 8 mulai muncul, membawa fitur baru: Gunakan ekspresi lambda (JSR-335) untuk pemrograman fungsional. Hari ini kita akan membahas bagian dari Lambda: Ekstensi Virtual, juga dikenal sebagai metode bek. Fitur ini memungkinkan Anda untuk mengimplementasikan metode penyediaan metode dalam definisi antarmuka. Misalnya, Anda dapat mendefinisikan metode untuk antarmuka yang ada (seperti daftar dan peta) sehingga pengembang lain tidak perlu mengimplementasikan metode ini, yang agak seperti abstrak, tetapi sebenarnya merupakan antarmuka. Tentu saja, Java 8 secara teoritis kompatibel dengan perpustakaan yang ada.
Metode ekstensi virtual membawa beberapa karakteristik warisan ke Java. Mungkin Anda bisa melihat bayangan warisan berganda melalui fitur ini. Tetapi Anda masih dapat mensimulasikan warisan dari keadaan contoh. Saya akan menjelaskan warisan negara melalui mixin dalam artikel berikutnya secara rinci.
Apa yang dicampur dalam mixin?
Pencampuran adalah kelas abstrak dari kombinasi. Misalnya, jika Anda memiliki kelas untuk menunjukkan "kuda", Anda dapat menempelkan kelas ini untuk membuat contoh "kuda", dan kemudian memperluasnya dengan mewarisi seperti "garasi" dan "kebun".
Val myhouse = rumah baru dengan garasi dengan taman
Dari warisan mixin bukan spesifikasi spesifik, ini hanyalah metode yang digunakan untuk menambahkan berbagai fungsi ke kategori yang ada. Di OOP, dengan mixin, Anda memiliki keterbacaan kelas melalui itu.
Misalnya, ada metode mixin dalam modul socketserver python.
Class forkingpserver (forkingmixin, udpserver): passclass forkingtcpserver (forkingmixin, tcpserver): pass class threadingudserver (threadMixin): passclass threadscserver (threadingmixin, tcpserver): passclass
Apa itu metode ekstensi virtual?
Java 8 akan memperkenalkan konsep ekstensi virtual, juga disebut metode public defender.
VEM bertujuan untuk menyediakan metode default untuk antarmuka Java. Perpustakaan partai ketiga seperti Hibernate tidak perlu mengulangi semua metode API koleksi ini karena telah memberikan beberapa metode default.
Berikut ini adalah contoh bagaimana mendefinisikan metode dalam antarmuka:
Koleksi Antarmuka Publik <T> Memperluas Iterable <T> {<r> Collection <r> Filter (Predikat <T> P) Default {Return Collections.
Simulasi campuran Java 8
Sekarang kita datang untuk mencapai efek beragam melalui VEM, tetapi peringatan sebelumnya adalah: Tolong jangan gunakan di tempat kerja!
Implementasi berikut ini tidak aman, dan mungkin ada masalah kebocoran memori, yang tergantung pada kode hash dan sama dengan metode yang Anda tentukan di kelas.
Pertama -tama, kami mendefinisikan definisi metode (simulasi keadaan kacang) dan memberikan metode:
Antarmuka publik switchablemixin {boolean isactivated () default {return switchable.isactivated (this);} void setactivated (boolean aktivitas) fault {switchable.setactivated (ini, diaktifkan);}}
Kemudian kami mendefinisikan kelas alat yang berisi instance peta untuk menyimpan asosiasi instance dan status.
Public Kelas Akhir {Private Static Final Map <SwitchableMixin, SwitchableDeviceState> Switch_States = HashMap baru <() (); Aktivitas;} public void setActivated (perangkat switchablemixin, boolean diaktifkan) {switchableDeviceState = switch_states.get (perangkat); .Activated = diaktifkan;} kelas private static switchableDevicestate {private boolean diaktifkan;}}
Berikut adalah kasus penggunaan yang menyoroti warisan negara:
Perangkat kelas statis privat {} kelas statis privat Devicea memperluas perangkat implement switchablemixin {} private static class deviceB memperluas perangkat implemeablemixin {}
"Hal yang sama sekali berbeda"
Implementasi di atas tampaknya normal, tetapi arsitek bahasa Java Oracle Brian Goetz mengajukan pertanyaan bahwa implementasi saat ini tidak dapat bekerja (dengan asumsi keselamatan utas dan kebocoran memori telah diselesaikan)
Antarmuka FakebrokenMixin {peta statis <ficebrokenMixin, string> backingmap = collections. letakkan (name);}} antarmuka x memperluas runnable, falebrokenMixin {} x makex () {return () -> {System.println ("x");}; ();
Hasil apa yang akan Anda tebak kode ini akan ditampilkan setelah eksekusi?
Solusi keraguan
Sekilas, tidak ada masalah dengan kode implementasi ini. X adalah antarmuka yang hanya berisi satu metode, karena getName dan setName sudah memiliki definisi default, tetapi metode run dari antarmuka yang dapat dijalankan tidak ditentukan. Implementasi Metode Jalankan. Oleh karena itu, hasil yang Anda inginkan program ini setelah eksekusi adalah:
X1x2
Jika Anda menghapus panggilan metode GetName, maka hasil eksekusi menjadi:
Mytest $ 1@30ae8764mytest $ 1@123acf34
Dua baris ini menunjukkan bahwa eksekusi metode Makex berasal dari dua contoh yang berbeda, dan pada saat ini, OpenJDK 8 saat ini dihasilkan (di sini saya menggunakan OpenJDK 8 24.0-B07).
Dalam kasus apa pun, OpenJDK 8 saat ini tidak mencerminkan perilaku Java 8 akhir.
X2x2
Jika Anda tidak memanggil metode getName, itu akan ditampilkan:
Mytest $ $ lambda $ 1@5506d4ytest $ $ $ lambda $ 1@5506d4ea
Setiap metode Calling Makex tampaknya menjadi contoh lajang dari kelas internal anonim yang sama.
Karena selama kompilasi, ekspresi Lambda tidak menjalani terjemahan yang lengkap. Instruksi ini berisi semua informasi meta yang diperlukan tentang ekspresi LABDA saat runtime. Termasuk nama metode, jenis input dan output, dan metode yang disebut bootstrap. Metode bootstrap digunakan untuk menentukan contoh dari menerima metode ini. Setelah JVM mengeksekusi instruksi Invokedynamic, JVM akan menyesuaikan metode metafaktor lambda pada bootstrap tertentu.
Kembali ke pertanyaan sekarang, ekspresi lambda berubah menjadi metode statis pribadi, () -> {System.out.println ("x");} ditransfer ke mytest:
Private static void lambda $ 0 () {System.out.println ("x");}
Jika Anda menggunakan parameter pribadi dengan perangkat kompilasi kontra-JAVAP dan Anda dapat melihat metode ini, Anda juga dapat menggunakan parameter -c untuk melihat konversi yang lebih lengkap.
Saat Anda menjalankan program, JVM memanggil metode Lambda Metafactory untuk mencoba menjelaskan instruksi Invokedynamic. Dalam contoh kami, ketika Makex dipanggil untuk pertama kalinya, metode Lambda Metafactory menghasilkan instance dari X dan secara dinamis menghubungkan metode RUN ke metode Lambda $ 0 Dalam memori, jadi contoh panggilan kedua Anda sama dengan pertama kali.
Apakah Anda memperbaikinya? Apakah ada solusi?
Tidak ada perbaikan langsung atau solusi untuk masalah ini. Meskipun program Java 8 Oracle default-xdlambdatomethod, karena parameter ini bukan bagian dari spesifikasi JVM, implementasi berbagai pemasok dan JVM berbeda. Untuk ekspresi Lambda, satu -satunya hal yang dapat Anda harapkan adalah mengimplementasikan metode antarmuka Anda di kelas.
Metode lain
Sejauh ini, meskipun tiruan kami dari mixin tidak dapat kompatibel dengan Java 8, masih mungkin untuk menambahkan beberapa layanan melalui beberapa warisan dan janji temu untuk ada. Metode ini adalah pola bidang virtual (mode bidang virtual).
Jadi lihatlah switchable kami.
antarmuka switchable {boolean isActive ();
Kami membutuhkan antarmuka yang dapat dialihkan dan menyediakan metode abstraksi tambahan untuk kembali ke implementasi yang dapat dialihkan. Metode terintegrasi berisi definisi default.
Public Interface SwitchableView memperluas {switchable getswitchable ();
Selanjutnya, kami membuat implementasi yang dapat dialihkan lengkap:
Public SwitchableImpl mengimplementasikan switchable {private boolean aktif;
Ini adalah contoh mode bidang virtual kami:
Perangkat Kelas Publik {} Public Class Devicea Memperluas Perangkat Imbalan SwitchableView {Private SwitchableableImpl (); Switchable getswitchable () {return switchable;}}
sebagai kesimpulan
Dalam artikel ini, kami menggunakan dua metode untuk menambahkan beberapa layanan melalui metode ekspansi virtual Java 8. Metode pertama menggunakan peta untuk menyimpan status instan. Metode lain adalah menggunakan mode bidang virtual untuk mengembalikan contoh implementasi akhir melalui pengambil abstrak. Metode kedua lebih mandiri dan lebih aman.
Metode Ekstensi Virtual adalah fitur baru dari Java.