昨天講了 java 使用 Jnative.jar 包方式調用c代碼,後來又看了使用JNI的方式,這裏再做個小結。
網上例子demo講解很多,但是都不詳細,簡直誤人子弟,也是醉了!!!還是要自己研究。
1、其實Jnative方式是對JNI進行了一層封裝,便於使用,直接通過接口就可以了,程序員用起來方便啊。我發現xxx.c 文件裏面的是使用C語言編寫的,而使用JNI 實現的xxx.c 是用c++編寫的。反正對c、c++來說,我是個菜鳥,大概知道就行了。
2、開始寫demo
首先需要安裝環境啊,我沒有vc++環境,使用的是mingw,安裝這個是爲了可以用命令 g++/gcc 來編譯c文件。
g++ : .c/.c++ 命令
gcc: 最好只針對.c文件
命令參考:
http://blog.csdn.net/u013378306/article/details/52424826
科普:
xxx.h 頭文件
xxx.c c/c++語言編寫的源代碼
xxx.cpp 這個裏面的代碼最好是c++編寫的
xxx.o 鏈接文件
xxx.dll 生成dll文件
xxx.exe 可執行文件
1)寫java 代碼
package com.test;
public class TestNative {
public native void sayHello();
static {
System.loadLibrary("Hello");// 加載生成的dll文件
}
public static void main(String[] args) {
new TestNative().sayHello();
}
}
2)java代碼生成.h 的頭文件
javah com.test.TestNative
回車後生成:com_test_TestNative.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class com_test_TestNative */
#ifndef _Included_com_test_TestNative
#define _Included_com_test_TestNative
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_test_TestNative
* Method: sayHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_test_TestNative_sayHello
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
這個一看就知道是C++代碼!!!
3)編寫實現.h頭文件的 .c代碼com_test_TestNative.c
#include "jni.h"
#include "com_test_TestNative.h"
JNIEXPORT void JNICALL Java_com_test_TestNative_sayHello(JNIEnv *env,
jobject obj) {
puts("c++");
return;
}
注:
這裏注意需要把jdk裏面的jni.h、jni_md.h 2個文件拷貝過來,估計是C語言添加的引用。
C++輸出方式有2種:
PUTS輸出和COUT輸出
但是網上demo都是用cout,這個需要
#include <iostream.h>
文件,我一直報錯
fatal error: iostream.h: No such file or directory
#include <iostream.h>
^
compilation terminated.
尼瑪,貌似需要vc環境???
後來改成puts命令,不需要#include<iostream.h>
這裏我認爲有錯。c++代碼(xxx.cpp文件)應該使用這種方式
#include<iostream>
using namespace std;
所以如果你要是使用cout 方式輸出,需要使用#include <iostream>
using namespace std;
文件後綴必須修改成
xxx.cpp (C++語言)
代碼修改:
#include <iostream>
using namespace std;
//#include "jni.h"
#include "com_test_TestNative.h"
JNIEXPORT void JNICALL Java_com_test_TestNative_sayHello(JNIEnv *env,
jobject obj) {
//puts("c++");
cout<<"helloworld"<<endl;
return;
}
4)有了
com_test_TestNative.c 文件認爲可以和Jnative一樣,剛開始使用
C:\Users\lihui20\Downloads\mingw>gcc -Wall -shared C:\Users\lihui20\Downloads\mi
ngw\com_test_TestNative.c -o Hello.dll
命令來一次性將
com_test_TestNative.c文件生成Hello.dll文件,
但是後來發現運行時候一直報錯。
Exception in thread “main” java.lang.UnsatisfiedLinkError: com.test.TestNative.sayHello()V
at com.test.TestNative.sayHello(Native Method)
at com.test.TestNative.main(TestNative.java:11)
不知道爲什麼????
百度發現需要分2步:
.c—> .o
C:\Users\lihui20\Downloads\mingw>gcc -c C:\Users\lihui20\Downloads\mingw\com_tes
t_TestNative.c
.o—> .dll
C:\Users\lihui20\Downloads\mingw> gcc -Wl,–add-stdcall-alias -shared -o Hello.dll C:\Users\lihui20\Downloads\mingw\com_test_TestNative.o
注意:如果你是.cpp文件格式,生成.o文件後,必須使用g++,生成 .dll文件
D:\test>g++ -Wl,-add-stdcall-alias -shared -o Helloworld.dll com_test_TestNative.o
如果你使用gcc報錯如下:
D:\test>gcc -Wl,--add-stdcall-alias -shared -o Hello.dll com_test_TestNative.o
com_test_TestNative.o:com_test_TestNative.cpp:(.text+0x11): undefined reference
to `std::cout'
com_test_TestNative.o:com_test_TestNative.cpp:(.text+0x16): undefined reference
to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::cha
r_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*
)'
com_test_TestNative.o:com_test_TestNative.cpp:(.text+0x1d): undefined reference
to `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char
_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)'
com_test_TestNative.o:com_test_TestNative.cpp:(.text+0x24): undefined reference
to `std::ostream::operator<<(std::ostream& (*)(std::ostream&))'
com_test_TestNative.o:com_test_TestNative.cpp:(.text+0x3c): undefined reference
to `std::ios_base::Init::~Init()'
com_test_TestNative.o:com_test_TestNative.cpp:(.text+0x5d): undefined reference
to `std::ios_base::Init::Init()'
collect2.exe: error: ld returned 1 exit status
把生成的Hello.dll 文件放在項目最外層目錄:
E:\ecplicespace\FileExplorer-master\TestJNIdemo
運行:
c++
這裏java使用jni方式調用c++代碼成功。