在java程序中,我們可以通過JNI實現(xiàn)一些用java語言不便實現(xiàn)的功能。通常有以下幾種情況我們需要使用JNI來實現(xiàn)。 標(biāo)準(zhǔn)的java類庫沒有提供你的應(yīng)用程序所需要的功能,通常這些功能是平臺相關(guān)的 你希望使用一些已經(jīng)有的類庫或者應(yīng)用程序,而他們并非用java語言編寫的 程序的某些部分對速度要求比較苛刻,你選擇用匯編或者c語言來實現(xiàn)并在java語言中調(diào)用他們 下面我們開始編寫HelloWorld程序,由于涉及到要編寫c/c++代碼因此我們會在開發(fā)中使用Microsoft VC++工具。編寫java代碼,我們在硬盤上建立一個hello目錄作為我們的工作目錄,首先我們需要編寫自己的java代碼,在java代碼中我們會聲明native方法,代碼非常簡單。如下所示 class HelloWorld { public native void displayHelloWorld(); static { System.loadLibrary("hello"); } public static void main(String[] args) { new HelloWorld().displayHelloWorld(); } } 注意我們的displayHelloWorld()方法的聲明,它有一個關(guān)鍵字native,表明這個方法使用java以外的語言實現(xiàn)。方法不包括實現(xiàn),因為我們要用c/c++語言實現(xiàn)它。注意System.loadLibrary("hello")這句代碼,它是在靜態(tài)初始化塊中定義的,系統(tǒng)用來裝載hello共享庫,這就是我們在后面生成的hello.dll(如果在其他的操作系統(tǒng)可能是其他的形式,比如hello.so) 編譯java代碼 javac HelloWorld.java 生成HelloWorld.class文件 創(chuàng)建.h文件 這一步中我們要使用javah命令生成.h文件,這個文件要在后面的c/c++代碼中用到,我們運行 javah HelloWorld。這樣我們可以看到在相同目錄下生成了一個HelloWorld.h文件,文件內(nèi)容如下 在此我們不對他進(jìn)行太多的解釋。 /* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class HelloWorld */ #ifndef _Included_HelloWorld #define _Included_HelloWorld #ifdef __cplusplus extern "C" { #endif /* * Class: HelloWorld * Method: displayHelloWorld * Signature: ()V */ JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif 編寫本地實現(xiàn)代碼 在這部分我們要用C/C++語言實現(xiàn)java中定義的方法,我們在VC++中新建一個Project,然后創(chuàng)建一個HelloWorldImp.cpp文件,內(nèi)容如下 #include #include "HelloWorld.h" #include JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld(JNIEnv *env, jobject obj) { printf("Hello world!\n"); return; } 注意我們這里include了 jni.h和剛才得到的HelloWorld.h文件。因此你要在VC++里面設(shè)置好,jni.h在JAVA_HOME/include里面。編譯通過后再生成hello.dll文件。 運行java程序 把上面生成的hello.dll文件復(fù)制到我們的工作目錄,這時候我們的目錄中包括HelloWorld.java,HelloWorld.class和hello.dll文件。運行java HelloWorld命令,則可在控制臺看到Hello world| 的輸出了。運行VC++; 文件---新建---選“win32 console application”(控制臺程序)---在右方設(shè)置好路徑并輸入工程名---確定 接下來的幾個提示框點確定就行了,那是提示是否要用VC++提供的框架之類的 在左邊的工作空間中選“FILEVIEW”標(biāo)簽項,點開“+”號,右鍵點擊“SOURCE FILES”,選“添加文件到目錄”,此即添加你要建立的C++源程序文件,會提示你沒有文件,是否添加,你點是,輸入文件名保存就OK了 然后SOURCE FILES下就出現(xiàn)了你剛才建立的*.CPP文件,雙擊,輸入代碼. 以下就是點”組建”菜單中的”編譯”、”組建”等命令進(jìn)行調(diào)試了。 相信你會了。
創(chuàng)新互聯(lián)公司長期為1000+客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為武清企業(yè)提供專業(yè)的成都做網(wǎng)站、成都網(wǎng)站設(shè)計,武清網(wǎng)站改版等技術(shù)服務(wù)。擁有10余年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。
Jython(原JPython),是一個用Java語言寫的Python解釋器。 在沒有第三方模塊的情況下,通常選擇利用Jython來調(diào)用Python代碼, 它是一個開源的JAR包,你可以到官網(wǎng)下載 一個HelloPython程序 importorg.python.util.PythonInterpreter; publicclassHelloPython{ publicstaticvoidmain(String[]args){ PythonInterpreterinterpreter=newPythonInterpreter(); interpreter.exec("print('hello')"); } } 什么是PythonInterpreter?它的中文意思即是“Python解釋器”。我們知道Python程序都是通過解釋器來執(zhí)行的,我們在Java中創(chuàng)建一個“解釋器”對象,模擬Python解釋器的行為,通過exec("Python語句")直接在JVM中執(zhí)行Python代碼,上面代碼的輸出結(jié)果為:hello在Jvm中執(zhí)行Python腳本 interpreter.execfile("D:/labs/mytest/hello.py");如上,將exec改為execfile就可以了。需要注意的是,這個.py文件不能含有第三方模塊,因為這個“Python腳本”最終還是在JVM環(huán)境下執(zhí)行的,如果有第三方模塊將會報錯:javaImportError:Nomodulenamedxxx 僅在Java中調(diào)用Python編寫的函數(shù) 先完成一個hello.py代碼: defhello(): return'Hello'在Java代碼中調(diào)用這個函數(shù): importorg.python.core.PyFunction; importorg.python.core.PyObject; importorg.python.util.PythonInterpreter; publicclassHelloPython{ publicstaticvoidmain(String[]args){ PythonInterpreterinterpreter=newPythonInterpreter(); interpreter.execfile("D:/labs/hello.py"); PyFunctionpyFunction=interpreter.get("hello",PyFunction.class);//第一個參數(shù)為期望獲得的函數(shù)(變量)的名字,第二個參數(shù)為期望返回的對象類型 PyObjectpyObject=pyFunction.__call__();//調(diào)用函數(shù) System.out.println(pyObject); } } 上面的代碼執(zhí)行結(jié)果為:Hello 即便只是調(diào)用一個函數(shù),也必須先加載這個.py文件,之后再通過Jython包中所定義的類獲取、調(diào)用這個函數(shù)。 如果函數(shù)需要參數(shù),在Java中必須先將參數(shù)轉(zhuǎn)化為對應(yīng)的“Python類型”,例如: __call__(newPyInteger(a),newPyInteger(b))a,b的類型為Java中的int型,還有諸如:PyString(Stringstring)、PyList(Iteratoriter)等。 詳細(xì)可以參考官方的api文檔。 包含第三方模塊的情況:一個手寫識別程序 這是我和舍友合作寫的一個小程序,完整代碼在這里:,界面上引用了corejava上的一段代碼。Python代碼是舍友寫的,因為在Python程序中使用了第三方的NumPy模塊,導(dǎo)致無法通過Jython執(zhí)行。下面這個方法純粹是個人思路,沒有深入查資料。核心代碼如下: importjava.io.*; classPyCaller{ privatestaticfinalStringDATA_SWAP="temp.txt"; privatestaticfinalStringPY_URL=System.getProperty("user.dir")+"\\test.py"; publicstaticvoidwriteImagePath(Stringpath){ PrintWriterpw=null; try{ pw=newPrintWriter(newFileWriter(newFile(DATA_SWAP))); }catch(IOExceptione){ e.printStackTrace(); } pw.print(path); pw.close(); } publicstaticStringreadAnswer(){ BufferedReaderbr; Stringanswer=null; try{ br=newBufferedReader(newFileReader(newFile(DATA_SWAP))); answer=br.readLine(); }catch(FileNotFoundExceptione){ e.printStackTrace(); }catch(IOExceptione){ e.printStackTrace(); } returnanswer; } publicstaticvoidexecPy(){ Processproc=null; try{ proc=Runtime.getRuntime().exec("python"+PY_URL); proc.waitFor(); }catch(IOExceptione){ e.printStackTrace(); }catch(InterruptedExceptione){ e.printStackTrace(); } } //測試碼 publicstaticvoidmain(String[]args)throwsIOException,InterruptedException{ writeImagePath("D:\\labs\\mytest\\test.jpg"); execPy(); System.out.println(readAnswer()); } } 實際上就是通過Java執(zhí)行一個命令行指令。
java中要多次調(diào)用函數(shù)(方法),無參數(shù)的函數(shù)(方法)只需寫上函數(shù)名即可,有參數(shù)的函數(shù)(方法)把參數(shù)傳進(jìn)來即可。
具體事例代碼如下:
public class Demo {
public static void main(String[] args) {
int a = a(2);//第一次調(diào)用
int b = a(4);//第二次調(diào)用
}
private static int a(int i){
return i;
}
}
要注意的是:在調(diào)用沒有返回值的函數(shù)(方法)時,不能給變量賦值,因為函數(shù)(方法)本身沒有返回值,就沒有值賦值給變量了。
1、在Java項目中新建一個類。然后在調(diào)用類中先進(jìn)行被調(diào)用類實例化,然后通過實例化的對象訪問。
2、在Java項目中新建一個類,將該類中需要被調(diào)用的方法設(shè)置為靜態(tài)(static),加了static后,就可以用類名直接調(diào)用。然后在調(diào)用類中直接通過類名進(jìn)行訪問。3、這樣就可以讓Java項目另一個類中的代碼跟這個類里面的代碼一起執(zhí)行了。