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