win7下java通過JNI調用C代碼

昨天講了 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++代碼成功。

發佈了49 篇原創文章 · 獲贊 49 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章