JNI详解------完整Demo

为什么要用JNI?因为有些功能JAVA无法提供,比如对扫描仪驱动,我现在就是要搞这个,网上给的例子都是SB.我气不过,便要自己去搞.感觉很悲剧.搜来想去,只能想办法通过C/C++来操作,然后用JAVA去调用C.这就需要JNI了.

 

什么是JNI?

JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++).这是百度百科上说的.通俗来说,就是JAVA调用C/C++函数的接口.如果你要想调用C系列的函数,你就必须遵守这样的约定.

JNI接口都长什么样?

就一个native的关键字.

public  class NativeDemo {
	{
		/**
		 * 系统加载其他的语言的函数
		 */
		System.load("C:\\Users\\Administrator\\Desktop\\com\\Hello.dll");
	}
	/**
	 * 就这个natice关键字.标记了这个接口,看起来像是abstract
	 */
	public native void sayHello();
	
	
	public static void main(String[] args) {
		new NativeDemo().sayHello();
	}
}

静态代码块先不讲。先看native方法。

sayHello()方法加了一个关键字native,就代表是一个native接口.执行这个方法时,会根据jni.h来找到真正的C来编写的sayHello()的实际函数.

jni.h是什么?

它实际上就存在%JAVA_HOME%\bin\include下面的一个文件,另外还有个%JAVA_HOME%\bin\include\win32下的jni_md.h.

这东西不说其他的作用,我也不清楚,只知道它里面存储了大量的函数和对象,它有个很好的方法就是通过native接口名,获取C函数.

打个比方类似如下:

public static String getCMethod(String javaMethodName);

它可以根据你的java接口,找到C函数并调用.

但这就意味着,你不能在C里随意写函数名,因为如果你写的java方法叫native aaa();C函数也叫aaa();但jni.h通过getCMethod(String javaMethodName)去找的结果是xxx();那这样就无法调用了.

既然不能随意写,怎么办?

没事,jdk提供了一个通过java方法生成c函数接口名的工具javah.

javah是什么?

就像java是运行main方法一样,javah就是提供具有native method的java对象的c函数接口.

dos命令如下:

javac NativeDemo.java
javah NativeDemo

这个命令可以提供一个c函数的接口.

上面那个NativeDemo被javah了之后就生成了一个文件Hello.h(可能我改了名字),就是C函数的接口.里面有方法名和返回值什么的.

Hello.h长什么样?

/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class NativeDemo */

#ifndef _Included_NativeDemo
#define _Included_NativeDemo
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     NativeDemo
 * Method:    sayHello
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_NativeDemo_sayHello
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

 

最重要的C函数接口就是这样:JNIEXPORT void JNICALL Java_NativeDemo_sayHello(JNIEnv *, jobject);

JNIEXPORT :在Jni编程中所有本地语言实现Jni接口的方法前面都有一个"JNIEXPORT",这个可以看做是Jni的一个标志,至今为止没发现它有什么特殊的用处。

void :这个学过编程的人都知道,当然是方法的返回值了。

JNICALL :这个可以理解为Jni 和Call两个部分,和起来的意思就是 Jni调用XXX(后面的XXX就是JAVA的方法名)。

Java_NativeDemo_sayHello:这个就是被上一步中被调用的部分,也就是Java中的native 方法名,这里起名字的方式比较特别,是:包名+类名+方法名。

JNIEnv * env:这个env可以看做是Jni接口本身的一个对象,jni.h头文件中存在着大量被封装好的函数,这些函数也是Jni编程中经常被使用到的,要想调用这些函数就需要使用JNIEnv这个对象。例如:env->GetObjectClass()。(详情请查看jni.h)

jobject obj:代表着native方法的调用者,本例即new NativeDemo();但如果native是静态的,那就是NativeDemo.class .

也就是说,我们的native sayHello()方法实际上是运行C的Java_NativeDemo_sayHello()这个方法,我们是不能随意写C函数名的的,只能这样写。

接下来我们可以照着接口去写真正的函数方法了.新建Hello.cpp

/* Replace "dll.h" with the name of your header */
#include "Hello.h"
#include 
#include 

JNIEXPORT void JNICALL Java_NativeDemo_sayHello(JNIEnv *, jobject){
	using namespace std;
	cout << "Hello___________World";
} 

这个方法什么都没有做,就打印了一句话"Hello___________World"

然后将Hello.h和Hello.cpp编译运行出dll文件.生成Hello.dll

这个过程中可以能编译会出现问题.

说“jni.h”: No such file or directory:

你需要把jdk里面的那俩jni.h给拷贝过来,再编译,如果还出错.需要把Hello.h里的头部#include 改写成 #include "jni.h".由尖括号改成双引号,具体咋回事,咱不是C程序员不清楚.

运行下试试吧

这样你现在就拥有了下列文件

JNI详解------完整Demo_第1张图片

实际上你现在就只需要NativeDemo和Hello.dll就行了。

别急,还有一个。NativeDemo里的静态代码块请准确把dll库给load进去

System.load("C:\\Users\\Administrator\\Desktop\\com\\Hello.dll");

然后编译java,运行

C:\Users\Administrator\Desktop\com>javac NativeDemo.java

C:\Users\Administrator\Desktop\com>java NativeDemo
Hello___________World
C:\Users\Administrator\Desktop\com>

非常完美。C++里的打印被调用了。

你可能感兴趣的:([计算机]知识,[语言]JAVA_JVM,[utils],[语言]C++,[事件]扫描仪)