色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何用Rust通過JNI和Java進(jìn)行交互

jf_wN0SrCdH ? 來源:Rust語言中文社區(qū) ? 2023-10-17 11:41 ? 次閱讀

近期工作中有Rust和Java互相調(diào)用需求,這篇文章主要介紹如何用Rust通過JNI和Java進(jìn)行交互,還有記錄一下開發(fā)過程中遇到的一些坑。


JNI簡(jiǎn)單來說是一套Java與其他語言互相調(diào)用的標(biāo)準(zhǔn),主要是C語言,官方也提供了基于C的C++接口。 既然是C語言接口,那么理論上支持C ABI的語言都可以和Java語言互相調(diào)用,Rust就是其中之一。


關(guān)于JNI的歷史背景以及更詳細(xì)的介紹可以參考官方文檔


在Rust中和Java互相調(diào)用,可以使用原始的JNI接口,也就是自己聲明JNI的C函數(shù)原型,在Rust里按照C的方式去調(diào)用,但這樣寫起來會(huì)很繁瑣,而且都是unsafe的操作; 不過Rust社區(qū)里已經(jīng)有人基于原始的JNI接口,封裝好了一套safe的接口,crate的名字就叫jni,用這個(gè)庫來開發(fā)就方便多了


文中涉及的代碼放在了這個(gè)github倉庫https://github.com/metaworm/rust-java-demo


Rust JNI 工程配置


如果你熟悉Cargo和Maven,可以跳過這一節(jié),直接看我提供的github源碼即可

Rust工程配置


首先,通過cargo new java-rust-demo創(chuàng)建一個(gè)rust工程

然后切換到工程目錄cd java-rust-demo,并編輯Cargo.toml:修改類型為動(dòng)態(tài)庫、加上對(duì) jni crate 的依賴


	

[package] name = "rust-java-demo" version = "0.1.0" edition = "2021" [lib] crate-type = ['cdylib'] [dependencies] jni = {version = '0.19'}

重命名src目錄下的main.rslib.rs,Rust庫類型的工程編譯入口為 lib.rs,然后添加以下代碼


	

use jni::*; use jni::JNIEnv; #[no_mangle] pub unsafe extern "C" fn Java_pers_metaworm_RustJNI_init(env: JNIEnv, _class: JClass) { println!("rust-java-demo inited"); }



然后執(zhí)行cargo build構(gòu)建,生成的動(dòng)態(tài)庫默認(rèn)會(huì)位于target/debug目錄下,我這里用的linux系統(tǒng),動(dòng)態(tài)庫文件名為librust_java_demo.so,如果是Windows系統(tǒng),文件名為rust_java_demo.dll


這樣,我們第一個(gè)JNI函數(shù)就創(chuàng)建成功了! 通過Java_pers_metaworm_RustJNI_init這個(gè)導(dǎo)出函數(shù),給了Java的pers.metaworm.RustJNI這個(gè)類提供了一個(gè)native的靜態(tài)方法init; 這里只是簡(jiǎn)單地打印了一句話,后面會(huì)通過這個(gè)初始化函數(shù)添加更多的功能


Java工程配置


還是在這個(gè)工程目錄里,把Java部分的代碼放在java這個(gè)目錄下,在其中創(chuàng)建pers/metaworm/RustJNI.java文件


	

package pers.metaworm; public class RustJNI { static { System.loadLibrary("rust_java_demo"); } public static void main(String[] args) { init(); } static native void init(); }


我們使用流行的 maven 工具來構(gòu)建Java工程,在項(xiàng)目根目錄下創(chuàng)建 maven 的工程文件pom.xml


	

xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0modelVersion> <groupId>pers.metawormgroupId> <artifactId>RustJNIartifactId> <version>1.0-SNAPSHOTversion> <properties> <exec.mainClass>pers.metaworm.RustJNIexec.mainClass> <maven.compiler.source>1.8maven.compiler.source> <maven.compiler.target>1.8maven.compiler.target> <maven.compiler.encoding>UTF-8maven.compiler.encoding> properties> <dependencies> dependencies> <build> <sourceDirectory>javasourceDirectory> <plugins> <plugin> <groupId>org.apache.maven.pluginsgroupId> <artifactId>maven-compiler-pluginartifactId> <version>2.4version> <configuration> <encoding>UTF-8encoding> configuration> plugin> plugins> build> project>


運(yùn)行 DMEO 工程


上面的工程配置弄好之后,就可以使用cargo build命令構(gòu)建Rust提供的JNI動(dòng)態(tài)庫,mvn compile命令來編譯Java代碼


Rust和Java代碼都編譯好之后,執(zhí)行java -Djava.library.path=target/debug -classpath target/classes pers.metaworm.RustJNI來運(yùn)行


其中-Djava.library.path=target/debug指定了我們JNI動(dòng)態(tài)庫所在的路徑,-classpath target/classes指定了Java代碼的編譯輸出的類路徑,pers.metaworm.RustJNI是Java main方法所在的類


不出意外的話,運(yùn)行之后會(huì)在控制臺(tái)輸出init函數(shù)里打印的"rust-java-demo inited"


Java調(diào)用Rust


接口聲明


前面的Java_pers_metaworm_RustJNI_init函數(shù)已經(jīng)展示了如何給Java暴露一個(gè)native方法,即導(dǎo)出名稱為Java_<類完整路徑>_<方法名>的函數(shù),然后在Java對(duì)應(yīng)的類里聲明對(duì)應(yīng)的native方法


拓展:除了通過導(dǎo)出函數(shù)給Java提供native方法,還可以通過 RegisterNatives 函數(shù)動(dòng)態(tài)注冊(cè)native方法,對(duì)應(yīng)的jni封裝的函數(shù)為JNIEnv::register_native_methods,一般動(dòng)態(tài)注冊(cè)會(huì)在JNI_Onload這個(gè)導(dǎo)出函數(shù)里執(zhí)行,jvm加載jni動(dòng)態(tài)庫時(shí)會(huì)執(zhí)行這個(gè)函數(shù)(如果有的話)


當(dāng)在Java里首次調(diào)用native方法時(shí),JVM就會(huì)尋找對(duì)應(yīng)名稱的導(dǎo)出的或者動(dòng)態(tài)注冊(cè)的native函數(shù),并將Java的native方法和Rust的函數(shù)關(guān)聯(lián)起來;如果JVM沒找到對(duì)應(yīng)的native函數(shù),則會(huì)報(bào)java.lang.UnsatisfiedLinkError異常


為了演示,我們?cè)偬砑右恍┐a來覆蓋更多的交互場(chǎng)景


lib.rs


	

use jni::*; use jni::{jint, jobject, jstring}; use jni::JNIEnv; #[no_mangle] pub unsafe extern "C" fn Java_pers_metaworm_RustJNI_addInt( env: JNIEnv, _class: JClass, a: jint, b: jint, ) -> jint { a + b } #[no_mangle] pub unsafe extern "C" fn Java_pers_metaworm_RustJNI_getThisField( env: JNIEnv, this: JObject, name: JString, sig: JString, ) -> jobject { let result = env .get_field( this, &env.get_string(name).unwrap().to_string_lossy(), &env.get_string(sig).unwrap().to_string_lossy(), ) .unwrap(); result.l().unwrap().into_inner() }


RustJNI.java


	

package pers.metaworm; public class RustJNI { static { System.loadLibrary("rust_java_demo"); } public static void main(String[] args) { init(); System.out.println("test addInt: " + (addInt(1, 2) == 3)); RustJNI jni = new RustJNI(); System.out.println("test getThisField: " + (jni.getThisField("stringField", "Ljava/lang/String;") == jni.stringField)); System.out.println("test success"); } String stringField = "abc"; static native void init(); static native int addInt(int a, int b); native Object getThisField(String name, String sig); }


其中,addInt方法接收兩個(gè)int參數(shù),并返回相加的結(jié)果;getThisField是一個(gè)實(shí)例native方法,它獲取this對(duì)象指定的字段并返回


參數(shù)傳遞


從上一節(jié)的例子里可以看到,jni函數(shù)的第一個(gè)參數(shù)總是JNIEnv,很多交互操作都需要通過這個(gè)對(duì)象來進(jìn)行; 第二個(gè)參數(shù)是類對(duì)象(靜態(tài)native方法)或this對(duì)象(實(shí)例native方法); 從第三個(gè)參數(shù)開始,每一個(gè)參數(shù)對(duì)應(yīng)Java的native方法所聲明的參數(shù)


對(duì)于基礎(chǔ)的參數(shù)類型,可以直接用use jni::*提供的j開頭的系列類型來聲明,類型對(duì)照表:


Java 類型 Native 類型 類型描述
boolean jboolean unsigned 8 bits
byte jbyte signed 8 bits
char jchar unsigned 16 bits
short jshort signed 16 bits
int jint signed 32 bits
long jlong signed 64 bits
float jfloat 32 bits
double jdouble 64 bits
void void not applicable



對(duì)于引用類型(復(fù)合類型/對(duì)象類型),可以統(tǒng)一用jni::JObject聲明;JObject是對(duì)jobject的rust封裝,帶有生命周期參數(shù);對(duì)于String類型,也可以用 JString 來聲明,JString是對(duì)JObject的一層簡(jiǎn)單封裝


拋異常


前面的Java_pers_metaworm_RustJNI_getThisField函數(shù)里,用了很多unwrap,這在生產(chǎn)環(huán)境中是非常危險(xiǎn)的,萬一傳了一個(gè)不存在的字段名,就直接crash了;所以我們改進(jìn)一下這個(gè)函數(shù),讓他支持拋異常,出錯(cuò)的時(shí)候能讓Java捕獲到


	

#[no_mangle] pub unsafe extern "C" fn Java_pers_metaworm_RustJNI_getThisFieldSafely( env: JNIEnv, this: JObject, name: JString, sig: JString, ) -> jobject { let result = (|| { env.get_field( this, &env.get_string(name)?.to_string_lossy(), &env.get_string(sig)?.to_string_lossy(), )? .l() })(); match result { Ok(res) => res.into_inner(), Err(err) => { env.exception_clear().expect("clear"); env.throw_new("Ljava/lang/Exception;", format!("{err:?}")) .expect("throw"); std::null_mut() } } }


Java層的測(cè)試代碼為

        

try { System.out.println("test getThisFieldSafely: " + (jni.getThisFieldSafely("stringField", "Ljava/lang/String;") == jni.stringField)); jni.getThisFieldSafely("fieldNotExists", "Ljava/lang/String;"); } catch (Exception e) { System.out.println("test getThisFieldSafely: catched exception: " + e.toString()); }


通過env.throw_new("Ljava/lang/Exception;", format!("{err:?}"))拋出了一個(gè)異常,從JNI函數(shù)返回后,Java就會(huì)捕獲到這個(gè)異常; 代碼里可以看到在拋異常之前,調(diào)用了env.exception_clear()來清除異常,這是因?yàn)榍懊娴膅et_field已經(jīng)拋出一個(gè)異常了,當(dāng)env里已經(jīng)有一個(gè)異常的時(shí)候,后續(xù)再調(diào)用env的函數(shù)都會(huì)失敗,這個(gè)異常也會(huì)繼續(xù)傳遞到上層的Java調(diào)用者,所以其實(shí)這里沒有這兩句,直接返回null的話,Java也可以捕獲到異常;但我們通過throw_new可以自定義異常類型及異常消息

這其實(shí)不是一個(gè)典型的場(chǎng)景,典型的場(chǎng)景應(yīng)該是Rust里的某個(gè)調(diào)用返回了Error,然后通過拋異常的形式傳遞到Java層,比如除0錯(cuò)誤


	

#[no_mangle] pub unsafe extern "C" fn Java_pers_metaworm_RustJNI_divInt( env: JNIEnv, _class: JClass, a: jint, b: jint, ) -> jint { if b == 0 { env.throw_new("Ljava/lang/Exception;", "divide zero") .expect("throw"); 0 } else { a / b } }

Rust調(diào)用Java


創(chuàng)建對(duì)象、調(diào)用方法、訪問字段...


下面用一段代碼展示如何在Rust中創(chuàng)建Java對(duì)象、調(diào)用方法、獲取字段、處理異常等常見用法


	

#[allow(non_snake_case)] fn call_java(env: &JNIEnv) { match (|| { let File = env.find_class("java/io/File")?; // 獲取靜態(tài)字段 let separator = env.get_static_field(File, "separator", "Ljava/lang/String;")?; let separator = env .get_string(separator.l()?.into())? .to_string_lossy() .to_string(); println!("File.separator: {}", separator); assert_eq!(separator, format!("{}", std::MAIN_SEPARATOR)); // env.get_static_field_unchecked(class, field, ty) // 創(chuàng)建實(shí)例對(duì)象 let file = env.new_object( "java/io/File", "(Ljava/lang/String;)V", &[JValue::Object(env.new_string("")?.into())], )?; // 調(diào)用實(shí)例方法 let abs = env.call_method(file, "getAbsolutePath", "()Ljava/lang/String;", &[])?; let abs_path = env .get_string(abs.l()?.into())? .to_string_lossy() .to_string(); println!("abs_path: {}", abs_path); jni::Result::Ok(()) })() { Ok(_) => {} // 捕獲異常 Err(jni::JavaException) => { let except = env.exception_occurred().expect("exception_occurred"); let err = env .call_method(except, "toString", "()Ljava/lang/String;", &[]) .and_then(|e| Ok(env.get_string(e.l()?.into())?.to_string_lossy().to_string())) .unwrap_or_default(); env.exception_clear().expect("clear exception"); println!("call java exception occurred: {err}"); } Err(err) => { println!("call java error: {err:?}"); } } } #[no_mangle] pub unsafe extern "C" fn Java_pers_metaworm_RustJNI_callJava(env: JNIEnv) { println!("call java"); call_java(&env) }


總結(jié)一下常用的函數(shù),具體用法可以參考JNIEnv的文檔

  • 創(chuàng)建對(duì)象new_object

  • 創(chuàng)建字符串對(duì)象new_string

  • 調(diào)用方法call_methodcall_static_method

  • 獲取字段get_fieldget_static_field

  • 修改字段set_fieldset_static_field


要注意的是調(diào)用方法、創(chuàng)建對(duì)象等需要傳一個(gè)方法類型簽名,這是因?yàn)镴ava支持方法重載,同一個(gè)類里一個(gè)名稱的函數(shù)可能有多個(gè),所以需要通過類型簽名來區(qū)分,類型簽名的規(guī)則可以參考官方文檔


異常處理


call_java函數(shù)展示了如何在Rust中處理Java的異常: 通過JNIEnv對(duì)象動(dòng)態(tài)獲取字段或者調(diào)用方法,都會(huì)返回一個(gè)jni::Result類型,對(duì)應(yīng)的Error類型為jni::Error;如果Error是jni::JavaException則表明在JVM執(zhí)行過程中,某個(gè)地方拋出了異常,這種情況下就可以用exception_occurred函數(shù)來獲取異常對(duì)象進(jìn)行處理,然后調(diào)用exception_clear來清除異常,如果再返回到Java便可以繼續(xù)執(zhí)行


在非Java線程中調(diào)用Java


從Java中調(diào)用的Rust代碼,本身就處于一個(gè)Java線程中,第一個(gè)參數(shù)為JNIEnv對(duì)象,Rust代碼用這個(gè)對(duì)象和Java進(jìn)行交互; 實(shí)際應(yīng)用場(chǎng)景中,可能需要從一個(gè)非Java線程或者說我們自己的線程中去調(diào)用Java的方法,但我們的線程沒有JNIEnv對(duì)象,這時(shí)就需要調(diào)用JavaVM::attach_current_thread函數(shù)將當(dāng)前線程附加到JVM上,來獲得一個(gè)JNIEnv


	

#[no_mangle] pub unsafe extern "C" fn Java_pers_metaworm_RustJNI_callJavaThread(env: JNIEnv) { let vm = env.get_java_vm().expect("get jvm"); std::spawn(move || { println!("call java in another thread"); let env = vm.attach_current_thread().expect("attach"); call_java(&env); }); }


attach_current_thread函數(shù)返回一個(gè)AttachGuard對(duì)象,可以解引用為JNIEnv,并且在作用域結(jié)束drop的時(shí)候自動(dòng)調(diào)用detach_current_thread函數(shù);原始的AttachCurrentThreadJNI函數(shù),如果當(dāng)前線程已經(jīng)attach了,則會(huì)拋異常,jni crate里的JavaVM::attach_current_thread做了一層封裝,如果當(dāng)前已經(jīng)attach了,則會(huì)返回之前attach的對(duì)象,保證不會(huì)重復(fù)attach


JavaVM對(duì)象通過JNIEnv::get_java_vm函數(shù)獲取,可以在初始化的時(shí)候?qū)⑦@個(gè)變量存起來,給后續(xù)的其他線程使用


局部引用、全局引用與對(duì)象緩存


關(guān)于局部引用與全局引用的官方文檔


Rust提供的native函數(shù),傳過來的對(duì)象引用都是局部引用,局部引用只在本次調(diào)用JNI調(diào)用范圍內(nèi)有效,而且不能跨線程使用;如果跨線程,必須使用全局引用


可以通過JNIEnv::new_global_ref來獲取JClass、JObject的全局引用,這個(gè)函數(shù)返回一個(gè)GlobalRef對(duì)象,可以通過GlobalRef::as_object轉(zhuǎn)成JObject或者JClass等對(duì)象;GlobalRef對(duì)象drop的時(shí)候,會(huì)調(diào)用DeleteGlobalRef將JVM內(nèi)部的引用刪除


前面的代碼,從Rust調(diào)用Java方法都是通過名稱加方法簽名調(diào)用的,這種方式,寫起來很舒服,但運(yùn)行效率肯定是非常低的,因?yàn)槊看味家ㄟ^名稱去查找對(duì)應(yīng)的方法


其實(shí)JNI原始的C接口,是通過jobjectID、jclassID、jmethodID、jfieldID來和Java交互的,只不過是jni crate給封裝了一層比較友好的接口


如果我們對(duì)性能要求比較高,則可以在初始化的時(shí)候獲取一些JClass、JObject的全局引用,緩存起來,后面再轉(zhuǎn)成JClass、JObject來使用,千萬不要對(duì)jmethodID、jfieldID獲取全局引用,因?yàn)檫@倆都是通過jclassID生成的,其聲明周期和jclassID對(duì)應(yīng)的對(duì)象相同,不是需要GC的對(duì)象,如果對(duì)jmethodID獲取全局引用然后調(diào)用,會(huì)導(dǎo)致某些JVM Crash;對(duì)于jmethodID、jfieldID,則可以基于JClass、JObject的全局引用獲取,后面直接使用即可


獲取到這些全局的ID之后,就可以通過JNIEnv::call_method_unchecked系列函數(shù),來更高效地調(diào)用Java


我用Rust強(qiáng)大的宏,實(shí)現(xiàn)了這個(gè)過程,可以讓我們直接在Rust中以聲明的方式緩存的所需類及其方法ID


	

#[allow(non_snake_case)] pub mod cache { use anyhow::Context; use jni::Result as JniResult; use jni::*; use jni::JNIEnv; pub fn method_global_ref<'a>( env: JNIEnv<'a>, class: JClass, name: &str, sig: &str, ) -> JniResult'a>> { let method = env.get_method_id(class, name, sig)?.into_inner(); Ok(JMethodID::from(method.cast())) } pub fn static_method_global_ref<'a>( env: JNIEnv<'a>, class: JClass, name: &str, sig: &str, ) -> ::Result'a>> { let method = env.get_static_method_id(class, name, sig)?.into_inner(); Ok(JStaticMethodID::from(method.cast())) } macro_rules! gen_global_ref { (@method_type) => { JMethodID<'static> }; (@method_type static) => { JStaticMethodID<'static> }; (@method_ref) => { method_global_ref }; (@method_ref static) => { static_method_global_ref }; ( $( #[name = $classname:literal] class $name:ident { $($method:ident : $($modify:ident)* $sig:literal,)* } )* ) => { $( #[allow(non_snake_case)] pub struct $name { pub class: JClass<'static>, $(pub $method: gen_global_ref!(@method_type $($modify)*),)* } impl $name { pub fn from_env(env: JNIEnv<'static>) -> anyhow::Result<Self> { Self::from_class(env, env.find_class($classname)?) } pub fn from_class(env: JNIEnv<'static>, class: JClass) -> anyhow::Result<Self> { let cls = env.new_global_ref(class)?; let class = JClass::from(*cls.as_obj()); core::forget(cls); Ok(Self { class, $( $method: gen_global_ref!(@method_ref $($modify)*)( env, class, stringify!($method), $sig).context(stringify!($method) )?, )* }) } } // TODO: impl Drop )* pub struct CachedClasses { $(pub $name: $name,)* } impl CachedClasses { pub fn from_env(env: JNIEnv<'static>) -> anyhow::Result<Self> { Ok(Self { $($name: $name::from_env(env).context(stringify!($name))?,)* }) } } unsafe impl Sync for CachedClasses {} unsafe impl Send for CachedClasses {} } } gen_global_ref! { #[name = "java/lang/Thread"] class Thread { currentThread: static "()Ljava/lang/Thread;", getStackTrace: "()[Ljava/lang/StackTraceElement;", } #[name = "java/lang/StackTraceElement"] class StackTraceElement { getLineNumber: "()I", toString: "()Ljava/lang/String;", } #[name = "java/io/File"] class File { getAbsolutePath: "()Ljava/lang/String;", } } static mut CLASSES: Option<Box> = None; pub unsafe fn init(env: JNIEnv<'static>) -> anyhow::Result<Option<Box>> { Ok(CLASSES.replace(CachedClasses::from_env(env)?.into())) } pub fn get() -> &'static CachedClasses { unsafe { CLASSES.as_ref().expect("Cached Java Classed not inited") } } }



審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 接口
    +關(guān)注

    關(guān)注

    33

    文章

    8575

    瀏覽量

    151015
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2966

    瀏覽量

    104702
  • C語言
    +關(guān)注

    關(guān)注

    180

    文章

    7604

    瀏覽量

    136692
  • C++
    C++
    +關(guān)注

    關(guān)注

    22

    文章

    2108

    瀏覽量

    73618
  • Rust
    +關(guān)注

    關(guān)注

    1

    文章

    228

    瀏覽量

    6601

原文標(biāo)題:【Rust筆記】Rust與Java交互-JNI模塊編寫-實(shí)踐總結(jié)

文章出處:【微信號(hào):Rust語言中文社區(qū),微信公眾號(hào):Rust語言中文社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    聊聊Rust與C語言交互的具體步驟

    rust FFI 是rust與其他語言互調(diào)的橋梁,通過FFI rust 可以有效繼承 C 語言的歷史資產(chǎn)。本期通過幾個(gè)例子來聊聊
    發(fā)表于 07-06 11:15 ?1705次閱讀

    【NanoPi Duo開發(fā)板試用申請(qǐng)】智能家居,Java高級(jí)語言控制

    服務(wù)器進(jìn)行交互,并通過Android端進(jìn)行控制。 實(shí)現(xiàn)輕松的接入,為智能硬件助力,將底層硬件的控制通過j
    發(fā)表于 09-21 15:35

    請(qǐng)問Labview與Java交互是否可以實(shí)現(xiàn)?

    各位大佬,小弟目前在做畢業(yè)設(shè)計(jì)是關(guān)于人工智能的,本人想利用laview myrio 機(jī)器人的sensor 傳送數(shù)據(jù)到 java, 然后java進(jìn)行信息處理然后輸出一個(gè)相應(yīng)的信息,然后傳遞到labview 使得機(jī)器人
    發(fā)表于 08-13 17:09

    芯靈思SinlinxA33開發(fā)板的安卓控制LED-2-JNI基礎(chǔ)

    ,對(duì)應(yīng)于在java層使用native關(guān)鍵字聲明的方法的。直白的說,就是在Java層聲明,C/C++語言實(shí)現(xiàn)的。當(dāng)然,這個(gè)函數(shù)并不一般,它會(huì)通過JNI某種機(jī)制與
    發(fā)表于 02-22 16:55

    基于JNI的嵌入式手機(jī)軟件該如何去設(shè)計(jì)?

    Java的性能問題及幾種解決方案什么是JNI技術(shù)基于JNI的嵌入式手機(jī)軟件開發(fā)實(shí)例
    發(fā)表于 04-23 07:17

    何用 rust 語言開發(fā) stm32

    本文介紹如何用 rust 語言開發(fā) stm32。開發(fā)平臺(tái)為 linux(gentoo)。硬件準(zhǔn)備本文使用的芯片為 STM32F103C8T6。該芯片性價(jià)比較高,價(jià)格低廉,適合入門學(xué)習(xí)。需要
    發(fā)表于 11-26 06:20

    JNI如何實(shí)現(xiàn)Android stdio IIC與從機(jī)通信的呢

    RK3288如何實(shí)現(xiàn)JNI對(duì)接上層Java和下層的C++呢?JNI如何實(shí)現(xiàn)Android stdio IIC與從機(jī)通信的呢?
    發(fā)表于 03-04 06:04

    何用java映射創(chuàng)建java對(duì)象和調(diào)用java對(duì)象呢

    java是一種解析語言,java程序是通過java虛擬機(jī)解析.class的方式運(yùn)行起來。因此,java中就存在
    發(fā)表于 04-11 14:43

    java與c之間的數(shù)據(jù)交互

    最近作一個(gè)tiemsten數(shù)據(jù)庫的項(xiàng)目,用到了jni技術(shù)。在這個(gè)項(xiàng)目中,我們用java來寫界面和業(yè)務(wù)邏輯,用c語言寫數(shù)據(jù)庫odbc訪問。單純的odbc其實(shí)沒有什么難的,但是在java和c之間進(jìn)
    發(fā)表于 11-27 10:22 ?1788次閱讀

    JNI java調(diào)用so動(dòng)態(tài)庫方法

    JNI Java調(diào)用so包相關(guān)問題總結(jié),出現(xiàn)了很多問題,按照操作應(yīng)該不會(huì)發(fā)生不到so包的錯(cuò)誤,其實(shí)最后出現(xiàn)的也是說加載不到libpython2.7.x.so.1,我就納悶了,怎么和python扯上
    發(fā)表于 11-28 13:13 ?3517次閱讀

    RSA算法的JNI封裝步驟

    要求較高的算法往往是基于C/C++語言(與硬件關(guān)聯(lián)性更強(qiáng))實(shí)現(xiàn)的。如果應(yīng)用程序需要基于JAVA編程實(shí)現(xiàn)時(shí),這就會(huì)有一些矛盾。此時(shí),通過JNI技術(shù),Java開發(fā)者可以在不了解算法內(nèi)容的情
    的頭像 發(fā)表于 06-04 17:45 ?2194次閱讀
    RSA算法的<b class='flag-5'>JNI</b>封裝步驟

    Go/Rust挑戰(zhàn)Java/Python地位

    編程語言方面,Java 和 Python 仍然遙遙領(lǐng)先,并且分別微小增長(zhǎng)了 1.7% 和 3.4%;圍繞 Go (增長(zhǎng) 20%) 和 Rust (增長(zhǎng) 22%) 的興趣則大幅增加。報(bào)告稱,如果這種
    的頭像 發(fā)表于 03-06 10:19 ?698次閱讀

    何用Java播放聲音

    在本篇文章中,我們將學(xué)習(xí)如何用Java播放音樂,Java 聲音 API 的設(shè)計(jì)是為了流暢和連續(xù)地播放聲音,甚至是很長(zhǎng)的聲音。我們將使用 Java 提供的 Clip 和 SourceDa
    的頭像 發(fā)表于 10-09 10:56 ?3233次閱讀

    何用Java代碼調(diào)用

    CloneNotSupportedException ; 你敢說你沒用過這些方法?如果你用過,那你就是一定用過不是Java語言編寫的方法。 答案就是【native】關(guān)鍵詞,用此關(guān)鍵詞修飾的方法,多數(shù)情況就不是用Java實(shí)現(xiàn)的。 那么為什么要用 native 來修飾方法,
    的頭像 發(fā)表于 10-11 15:29 ?498次閱讀
    如<b class='flag-5'>何用</b><b class='flag-5'>Java</b>代碼調(diào)用

    何用Rust編寫一個(gè)ChatGPT桌面應(yīng)用(保姆級(jí)教程)

    用IDEA開發(fā)的java仔) 安裝 Rust 語言工具鏈:首先,請(qǐng)確保你已安裝了 Rust 編程語言工具鏈,包括 Rust 編譯器 (rustc) 和包管理工具 (cargo)。可以
    的頭像 發(fā)表于 09-25 11:19 ?343次閱讀
    如<b class='flag-5'>何用</b><b class='flag-5'>Rust</b>編寫一個(gè)ChatGPT桌面應(yīng)用(保姆級(jí)教程)
    主站蜘蛛池模板: 窝窝午夜色视频国产精品东北| 国产在线精品亚洲第一区| 十大禁止安装的黄台有风险| 国产成人久视频免费| 亚洲AV综合99一二三四区| 久久精品国产清白在天天线| 91精选国产| 色翁荡息又大又硬又粗又爽电影| 国产一区二区内射最近更新| 3DNagoonimation动漫| 日韩精品一区VR观看| 寂寞夜晚视频在线观看| 97人妻碰视频在线观看| 手机毛片在线| 久久精品国产免费播放| 菠萝蜜国际一区麻豆| 亚洲精品无码不卡在线播HE| 嫩草影院地址一二三| 国产高清精品自在久久| 在线免费国产| 少妇被阴内射XXXB少妇BB| 久久成人a毛片免费观看网站| GOGOGO高清免费播放| 亚洲 欧美 制服 校园 动漫| 蜜桃传媒在线观看| 国产精品成久久久久三级四虎| 在线观看免费视频a| 日日射夜夜干夜夜插在线播放| 精品久久综合1区2区3区激情| beeg日本老妇人| 亚洲精品乱码久久久久久v| 女人一级毛片免费视频观看| 国产亚洲精品久久精品录音| 99re精品视频在线播放视频| 性肥胖BWBWBW| 欧美精品九九99久久在免费线| 国产午夜在线视频| av天堂电影网| 亚洲免费片| 人与畜禽CROPROATION免费| 九九热在线视频观看这里只有精品|