


Bagaimana untuk menyelesaikan masalah panggil balik dalam JNA dalam penggunaan java lanjutan
Pengenalan
Apakah panggilan balik? Ringkasnya, panggilan balik ialah pemberitahuan panggil balik Apabila kami perlu memberitahu tugasan tertentu selepas kaedah selesai atau peristiwa dicetuskan, kami perlu menggunakan panggilan balik.
Bahasa yang anda paling mungkin melihat panggilan balik ialah javascript Pada asasnya dalam javascript, panggilan balik ada di mana-mana. Untuk menyelesaikan masalah neraka panggilan balik yang disebabkan oleh panggilan balik, janji telah diperkenalkan khas dalam ES6 untuk menyelesaikan masalah ini.
Untuk memudahkan interaksi dengan kaedah asli, JNA juga menyediakan Panggilan Balik untuk panggilan balik. Intipati panggilan balik dalam JNA ialah penunjuk kepada fungsi asli Melalui penunjuk ini, kaedah dalam fungsi asli boleh dipanggil.
Panggil Balik dalam JNA
Pertama lihat definisi Panggilan Balik dalam JNA:
public interface Callback { interface UncaughtExceptionHandler { void uncaughtException(Callback c, Throwable e); } String METHOD_NAME = "callback"; List<String> FORBIDDEN_NAMES = Collections.unmodifiableList( Arrays.asList("hashCode", "equals", "toString")); }
Semua kaedah Panggilan Balik perlu melaksanakan antara muka Panggilan Balik ini. Antara muka Panggilan Balik adalah sangat mudah Ia mentakrifkan antara muka dan dua sifat.
Mari lihat antara muka ini dahulu Nama antara muka ialah UncaughtExceptionHandler, dan terdapat kaedah uncaughtException di dalamnya. Antara muka ini digunakan terutamanya untuk mengendalikan pengecualian yang tidak ditangkap dalam kod panggil balik JAVA.
Perhatikan bahawa pengecualian tidak boleh dilemparkan dalam kaedah uncaughtException Sebarang pengecualian yang dilemparkan daripada kaedah ini akan diabaikan.
METHOD_NAME Medan ini menentukan kaedah untuk dipanggil melalui Panggilan Balik.
Jika terdapat hanya satu kaedah awam yang ditakrifkan dalam kelas Panggilan Balik, maka kaedah panggil balik lalai ialah kaedah ini. Jika berbilang kaedah awam ditakrifkan dalam kelas Panggilan Balik, kaedah dengan METHOD_NAME = "panggilan balik" akan dipilih sebagai panggilan balik.
Atribut terakhir ialah FORBIDDEN_NAMES. Menunjukkan bahawa nama dalam senarai ini tidak boleh digunakan sebagai kaedah panggil balik.
Pada masa ini nampaknya terdapat tiga nama kaedah yang tidak boleh digunakan, iaitu: "hashCode", "equals", dan "toString".
Panggil balik juga mempunyai adik beradik yang dipanggil DLLCallback Mari kita lihat definisi DLLCallback:
public interface DLLCallback extends Callback { @java.lang.annotation.Native int DLL_FPTRS = 16; }
DLLCallback digunakan terutamanya untuk mengakses Windows API.
Untuk objek panggil balik, kita perlu bertanggungjawab untuk melepaskan objek panggil balik sendiri. Jika kod asli cuba mengakses panggilan balik kitar semula, ia boleh menyebabkan VM ranap.
Aplikasi panggilan balik
Definisi panggil balik
Kerana panggilan balik dalam JNA sebenarnya memetakan penuding kepada fungsi dalam asli. Mula-mula, lihat penuding fungsi yang ditakrifkan dalam struct:
struct _functions { int (*open)(const char*,int); int (*close)(int); };
Dalam struktur ini, dua penunjuk fungsi ditakrifkan, dengan dua parameter dan satu parameter masing-masing.
Takrifan panggil balik JNA yang sepadan adalah seperti berikut:
public class Functions extends Structure { public static interface OpenFunc extends Callback { int invoke(String name, int options); } public static interface CloseFunc extends Callback { int invoke(int fd); } public OpenFunc open; public CloseFunc close; }
Kami mentakrifkan dua antara muka dalam Struktur yang diwarisi daripada Panggilan Balik, dan kaedah panggilan yang sepadan ditakrifkan dalam antara muka yang sepadan.
Kemudian lihat kaedah panggilan khusus:
Functions funcs = new Functions(); lib.init(funcs); int fd = funcs.open.invoke("myfile", 0); funcs.close.invoke(fd);
Selain itu, Panggilan Balik juga boleh digunakan sebagai nilai pulangan fungsi, seperti ditunjukkan di bawah:
typedef void (*sig_t)(int); sig_t signal(int signal, sig_t sigfunc);
Untuk penuding fungsi yang berasingan ini, kita perlu menyesuaikan Perpustakaan dan mentakrifkan Panggilan Balik yang sepadan di dalamnya, seperti yang ditunjukkan di bawah:
public interface CLibrary extends Library { public interface SignalFunction extends Callback { void invoke(int signal); } SignalFunction signal(int signal, SignalFunction func); }
Pemerolehan dan penggunaan panggilan balik
Jika panggilan balik ditakrifkan dalam Struktur, maka ia boleh Structure secara automatik instantiated apabila ia dimulakan, dan kemudian anda hanya perlu mengakses sifat yang sepadan daripada Structure.
Jika panggilan balik ditakrifkan dalam Perpustakaan biasa, ia adalah seperti berikut:
public static interface TestLibrary extends Library { interface VoidCallback extends Callback { void callback(); } interface ByteCallback extends Callback { byte callback(byte arg, byte arg2); } void callVoidCallback(VoidCallback c); byte callInt8Callback(ByteCallback c, byte arg, byte arg2); }
Dalam contoh di atas, kami menentukan dua panggilan balik dalam Perpustakaan, satu tanpa panggilan balik nilai pulangan, satu adalah panggilan balik yang mengembalikan bait.
JNA menyediakan kelas alat mudah untuk membantu kami mendapatkan Panggilan Balik Kelas alat ini ialah CallbackReference, dan kaedah yang sepadan ialah CallbackReference.getCallback, seperti yang ditunjukkan di bawah:
Pointer p = new Pointer("MultiplyMappedCallback".hashCode()); Callback cbV1 = CallbackReference.getCallback(TestLibrary.VoidCallback.class, p); Callback cbB1 = CallbackReference.getCallback(TestLibrary.ByteCallback.class, p); log.info("cbV1:{}",cbV1); log.info("cbB1:{}",cbB1);
Hasil output adalah seperti berikut. :
INFO com.flydean.CallbackUsage - cbV1:Antara muka proksi ke fungsi asli@0xffffffffc46eeefc (com.flydean.CallbackUsage$TestLibrary$VoidCallback)
UFO com.Ca.llflybdean c. antara muka ke fungsi asli@0xffffffffc46eeefc (com.flydean.CallbackUsage$TestLibrary$ByteCallback)
Dapat dilihat bahawa kedua-dua Panggilan Balik ini sebenarnya adalah proksi untuk kaedah asli. Jika anda melihat logik pelaksanaan getCallback secara terperinci:
private static Callback getCallback(Class<?> type, Pointer p, boolean direct) { if (p == null) { return null; } if (!type.isInterface()) throw new IllegalArgumentException("Callback type must be an interface"); Map<Callback, CallbackReference> map = direct ? directCallbackMap : callbackMap; synchronized(pointerCallbackMap) { Reference<Callback>[] array = pointerCallbackMap.get(p); Callback cb = getTypeAssignableCallback(type, array); if (cb != null) { return cb; } cb = createCallback(type, p); pointerCallbackMap.put(p, addCallbackToArray(cb,array)); // No CallbackReference for this callback map.remove(cb); return cb; } }
anda boleh melihat bahawa logik pelaksanaannya adalah untuk menentukan terlebih dahulu sama ada jenis itu adalah antara muka Jika ia bukan antara muka, ralat akan dilaporkan. Kemudian tentukan sama ada ia adalah pemetaan langsung. Malah, pelaksanaan semasa JNA adalah semua pemetaan antara muka, jadi logik seterusnya adalah untuk mendapatkan panggilan balik yang sepadan dengan penunjuk fungsi daripada pointerCallbackMap. Kemudian cari Panggilan Balik khusus mengikut jenis yang diluluskan.
Jika ia tidak ditemui, buat panggilan balik baharu dan akhirnya simpan panggilan balik yang baru dibuat dalam pointerCallbackMap.
Semua orang harus ambil perhatian bahawa terdapat parameter utama di sini yang dipanggil Penunjuk Apabila benar-benar menggunakannya, anda perlu menghantar penunjuk ke fungsi naitve sebenar. Dalam contoh di atas, demi kesederhanaan, kami menyesuaikan Penunjuk, yang tidak mempunyai banyak kepentingan praktikal.
如果真的要想在JNA中调用在TestLibrary中创建的两个call方法:callVoidCallback和callInt8Callback,首先需要加载对应的Library:
TestLibrary lib = Native.load("testlib", TestLibrary.class);
然后分别创建TestLibrary.VoidCallback和TestLibrary.ByteCallback的实例如下,首先看一下VoidCallback:
final boolean[] voidCalled = { false }; TestLibrary.VoidCallback cb1 = new TestLibrary.VoidCallback() { @Override public void callback() { voidCalled[0] = true; } }; lib.callVoidCallback(cb1); assertTrue("Callback not called", voidCalled[0]);
这里我们在callback中将voidCalled的值回写为true表示已经调用了callback方法。
再看看带返回值的ByteCallback:
final boolean[] int8Called = {false}; final byte[] cbArgs = { 0, 0 }; TestLibrary.ByteCallback cb2 = new TestLibrary.ByteCallback() { @Override public byte callback(byte arg, byte arg2) { int8Called[0] = true; cbArgs[0] = arg; cbArgs[1] = arg2; return (byte)(arg + arg2); } }; final byte MAGIC = 0x11; byte value = lib.callInt8Callback(cb2, MAGIC, (byte)(MAGIC*2));
我们直接在callback方法中返回要返回的byte值即可。
在多线程环境中使用callback
默认情况下, callback方法是在当前的线程中执行的。如果希望callback方法是在另外的线程中执行,则可以创建一个CallbackThreadInitializer,指定daemon,detach,name,和threadGroup属性:
final String tname = "VoidCallbackThreaded"; ThreadGroup testGroup = new ThreadGroup("Thread group for callVoidCallbackThreaded"); CallbackThreadInitializer init = new CallbackThreadInitializer(true, false, tname, testGroup);
然后创建callback的实例:
TestLibrary.VoidCallback cb = new TestLibrary.VoidCallback() { @Override public void callback() { Thread thread = Thread.currentThread(); daemon[0] = thread.isDaemon(); name[0] = thread.getName(); group[0] = thread.getThreadGroup(); t[0] = thread; if (thread.isAlive()) { alive[0] = true; } ++called[0]; if (THREAD_DETACH_BUG && called[0] == 2) { Native.detach(true); } } };
然后调用:
Native.setCallbackThreadInitializer(cb, init);
将callback和CallbackThreadInitializer进行关联。
最后调用callback方法即可:
lib.callVoidCallbackThreaded(cb, 2, 2000, "callVoidCallbackThreaded", 0);
Atas ialah kandungan terperinci Bagaimana untuk menyelesaikan masalah panggil balik dalam JNA dalam penggunaan java lanjutan. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas



Panduan Nombor Sempurna di Jawa. Di sini kita membincangkan Definisi, Bagaimana untuk menyemak nombor Perfect dalam Java?, contoh dengan pelaksanaan kod.

Panduan untuk Weka di Jawa. Di sini kita membincangkan Pengenalan, cara menggunakan weka java, jenis platform, dan kelebihan dengan contoh.

Panduan untuk Nombor Smith di Jawa. Di sini kita membincangkan Definisi, Bagaimana untuk menyemak nombor smith di Jawa? contoh dengan pelaksanaan kod.

Dalam artikel ini, kami telah menyimpan Soalan Temuduga Spring Java yang paling banyak ditanya dengan jawapan terperinci mereka. Supaya anda boleh memecahkan temuduga.

Java 8 memperkenalkan API Stream, menyediakan cara yang kuat dan ekspresif untuk memproses koleksi data. Walau bagaimanapun, soalan biasa apabila menggunakan aliran adalah: bagaimana untuk memecahkan atau kembali dari operasi foreach? Gelung tradisional membolehkan gangguan awal atau pulangan, tetapi kaedah Foreach Stream tidak menyokong secara langsung kaedah ini. Artikel ini akan menerangkan sebab -sebab dan meneroka kaedah alternatif untuk melaksanakan penamatan pramatang dalam sistem pemprosesan aliran. Bacaan Lanjut: Penambahbaikan API Java Stream Memahami aliran aliran Kaedah Foreach adalah operasi terminal yang melakukan satu operasi pada setiap elemen dalam aliran. Niat reka bentuknya adalah

Panduan untuk TimeStamp to Date di Java. Di sini kita juga membincangkan pengenalan dan cara menukar cap waktu kepada tarikh dalam java bersama-sama dengan contoh.

Kapsul adalah angka geometri tiga dimensi, terdiri daripada silinder dan hemisfera di kedua-dua hujungnya. Jumlah kapsul boleh dikira dengan menambahkan isipadu silinder dan jumlah hemisfera di kedua -dua hujungnya. Tutorial ini akan membincangkan cara mengira jumlah kapsul yang diberikan dalam Java menggunakan kaedah yang berbeza. Formula volum kapsul Formula untuk jumlah kapsul adalah seperti berikut: Kelantangan kapsul = isipadu isipadu silinder Dua jumlah hemisfera dalam, R: Radius hemisfera. H: Ketinggian silinder (tidak termasuk hemisfera). Contoh 1 masukkan Jejari = 5 unit Ketinggian = 10 unit Output Jilid = 1570.8 Unit padu menjelaskan Kirakan kelantangan menggunakan formula: Kelantangan = π × r2 × h (4

Spring Boot memudahkan penciptaan aplikasi Java yang mantap, berskala, dan siap pengeluaran, merevolusi pembangunan Java. Pendekatan "Konvensyen Lebih Konfigurasi", yang wujud pada ekosistem musim bunga, meminimumkan persediaan manual, Allo
