日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

本地方法(JNI)——从java 程序中调用C函数

發布時間:2023/12/3 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 本地方法(JNI)——从java 程序中调用C函数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【0】README

1) 本文部分文字描述 轉自 core java volume 2 , 旨在理解 本地方法——從java 程序中調用C函數 的基礎知識 ;
2) for source code, please visit https://github.com/pacosonTang/core-java-volume/tree/master/coreJavaAdvanced/chapter12/javaCassFuncOfC

【1】本地方法相關

1)本地代碼定義: 原則上說, 100% 純 java 的解決方案是非常好的, 但有時你也會想要編寫或使用其他語言的代碼, 這種代碼就稱為本地代碼;
2)我們建議只有在必需的時候才使用本地代碼, 特別是在以下三種情況的時候(cases):

  • c1)你的應用需要訪問的系統特性和設備通過java 平臺無法實現;
  • c2)你已經有了大量的測試過 和 調試過的 用另一種語言編寫的代碼, 并且知道如何將其導出到所有的目標平臺上;
  • c3)通過基準測試, 你發現所編寫的 java 代碼比用另一種語言編寫的等價代碼要慢很多;

3)java 本地接口(JNI): java 平臺有一個用于和本地C 代碼進行交互操作的 API, 稱為java 本地接口(JNI);


【2】從java 程序中調用C函數

1) 關鍵字native: java 使用 native 表示本地方法;

class HelloNative { public static native void greeting(); }

2)本地方法: 既可以是靜態的,也可以是非靜態的;
3)為了實現本地代碼: 需要編寫一個C 函數,你必須完全按照 java 虛擬機預期的那樣來命名這個函數。 其規則是(rules):

  • r1)使用完整的java 方法名:

    如 HelloNative.greeting; 如果屬于某個包還要添加包名, 如 com.corejava.HelloNative.greeting;

  • r2)用下劃線替換掉所有的句號, 并加上 Java_前綴, 如:

    Java_com_corejava_HelloNative_greeting;

  • r3)如果類名含有非 ASCII 字母或數字:

    如:’_’, ‘$’ 或是 大于 ‘\u007F’ 的 unicode 字符,用_0xxxx 來替代它們, xxxx 是該字符的unicode 值的 4個十六進制數序列;

Attention)

  • A1)如果你重載本地方法, 也就是說, 你用相同的名字提供多個本地方法, 那么你必須在名稱后面附加兩個下劃線, 后面再加上已編碼的參數類型;
  • A2) 看個荔枝: 如果你有一個本地方法 greeting 和 本地方法 greeting(int repeat), 那么第一個稱為 Java_HelloNative_greeting__, 第二個稱為 Java_HelloNative_greeting_I;
  • A3)javah程序:沒有人完成這些手工操作, javah 自動生成函數名;

4)java程序調用C函數的實現steps:

  • (javah導出類的頭文件可能拋出異常——java.lang.IllegalArgumentException: Not a valid class name, for solution, please visit http://blog.csdn.net/pacosonswjtu/article/details/50615988)

  • step1)用 javah 生成函數名:

  • 對以上代碼的分析(Analysis):

    • A1) 這個頭文件包含了函數 Java_HelloNative_greeting 的聲明;
    • A2) 字符串 JNIEXPORT 和 JNICALL 是在頭文件 jni.h 中定義的, 他們為那些來自動態裝載庫的導出函數標明了 依賴于編譯器的說明符;
  • step2)現在,需要將 函數原型從頭文件中 復制到源文件中, 并且給出函數的實現代碼(新建 HelloNative.c);

  • step3) 將本地C 代碼編譯到一個動態裝載庫中, 具體方法依賴于編譯器;

    • step3.1) Linux 下的 GNU C 編譯器:

      使用如下命令:(1) gcc -fPIC -I jdk/include -I jdk/include/linux -shared -o libHelloNative.so HelloNative.c 或
      (2.1) gcc -c -I /usr/java/jdk1.7/include/ -I /usr/java/jdk1.7/include/linux/ HelloNative.c
      (2.2) gcc -shared -fPIC -o HelloNative.so HelloNative.o

    • step3.2)使用windows 下的微軟編譯器:

      命令是: cl -I jdk/include -I >jdk/include/win32 -LD HelloNative.c -FeHelloNative.dll

    • step3.3)通過cygwin 環境下 將本地C 代碼編譯到動態裝載庫中:

      gcc -mno-cygwin -D __int64=”long long” -I jdk/include/win32 -shared -Wl, –add-stdcall-alias -o HelloNative.dll HelloNative.c

  • step4) 最后,我們要在程序中添加 一個對 System.loadLibrary 方法的調用。為了確保虛擬機第一次使用該類之前就會裝載這個庫, 需要使用 靜態初始化代碼塊。 如下所示:

Attention)如果運行在 Linux 下, 必須把當前目錄添加到庫路徑中。

  • A1)實現的方式可以是通過設置 LD_LIBRARY_PATH 環境變量:

    export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

  • A2)或者是設置 java.library.path 系統屬性:

    java -Djava.library.path=. HelloNativeTest

Conclusion) 總之,遵循下面的steps就可以將一個本地方法鏈接到 java 程序中:

  • step1)在 java類中聲明一個本地方法;

    package com.corejava.chapter12;public class HelloNative { public static native void greeting(); }
  • step2) 運行javah 以獲得包含該方法的 C 聲明的頭文件;

  • step2.1)編譯文件: javac com/corejava/chapter12/HelloNative.java

  • step2.2)javah生成該類的頭文件: javah com.corejava.chapter12.HelloNative

step3) 用 C 實現該本地方法:

  • step3.1)將 相應的方法原型(返回類型,方法名,參數列表) copy 到 .c 文件中,并實現該方法):
#include "com_corejava_chapter12_HelloNative.h" #include <stdio.h> JNIEXPORT void JNICALL Java_com_corejava_chapter12_HelloNative_greeting(JNIEnv * env, jclass) {printf("hello world ! this greeting is from native method by C"); }
  • step3.2)在linux環境下, 將本地C 代碼編譯到動態裝載庫中

    gcc -c -I /usr/java/jdk1.7/include/ -I /usr/java/jdk1.7/include/linux/ HelloNative.c
    gcc -shared -fPIC -o libHelloNative.so HelloNative.o

  • step4)將代碼置于 共享類庫中;

  • step5) 在 java 程序中 加載該類庫(java類中的main調用C函數)

    • Warning) 這里運行可能出錯,throw exception : java.lang.UnsatisfiedLinkError: no yourClassName in java.library.path , 這也就是 為什么本文先打印出了 java.library.path, 然后將 libHelloNative.so 添加到該共享庫中的原因;當然了, for detailed spec , you can also refer to http://blog.csdn.net/pacosonswjtu/article/details/50618033

Conclusion) 最后的工作目錄文件列表如下:

總結

以上是生活随笔為你收集整理的本地方法(JNI)——从java 程序中调用C函数的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。