`
tomotoboy
  • 浏览: 162396 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

JNI 和java native method入门

    博客分类:
  • Java
阅读更多
毫无疑问,Java是一门非常强大的语言,但是像C、C++等本地语言(这里称为native language)已经存在了很长一段时间,基于这些语言已经实现了大量的无价的应用。谁都不想重复历史的车轮对吧!如果java能够把那些基于native language的应用集成到自己的开发应用当中,那将会是一件皆大欢喜的事情,既节省人力又节省无力,何乐而不为呢?

怎么做呢?java native methods就是这把钥匙!
java native methods就是由其它语言实现的功能方法,而并非java。它可能由是C、C++或者汇编等实现。在win32上,这些功能的实现被编译成动态链接库(在Solaris上称之为共享对象),这样操作系统就可以像变魔术一样把它加载并链接到运行在JVM上的进程里。

JNI(java native interface)是jdk的一部分,它像胶水一样将java应用和其它本地应用结合在一起,它提供了能够促使双方进行交流的所有功能。JDK也提供了一些工具在java和本地语言之间的处理方法和数据类型的映射。在本地方,接口指针是每一个本地方法实现的第一个参数,通过它JNI功能才有效访问。

现在我们知道了Java提供JNI去集成java代码和本地代码,但是否我们应该想想怎么去用它?虽然JNI增加了项目开发的复杂度,同时还有其它的缺点。我们应该在必须使用它时才使用它。如果遇到下面任意一种情况,有经验的人就会想到使用JNI:
  • 当一些功能没有被java提供
  • 当开发人员不能承担用JAVA重写的代价,而想去用一些已经存在的安全的库。
  • 当性能成为一个大问题的时候。
  • 如果一个新的开发需要将已经存在的安全合法的应用移植到其它的平台上时。

当然我们需要保持理念:JNI不是唯一的能够让JAVA和本地语言集成的解决方案,这可真是一个如果、然后如果得问题。


现在让我们来看看需要哪些基本的步骤来实现JNI方法。在java种调用本地方式是非常简单的事情。首先你需要在java类中声明一个本地方法,然后使用System的loadLibrary方法去加载包含本地方法实现的库,java类的定义如下:
class sample{

		static{
	
			System.loadLibrary("sampleImp");
		}
	
		public native int sum(int[] a, int[] b);
		//rest of the class definition
	}


这里sum方法由native关键字修饰是为了说明该法不是由java,而是由其它语言实现的。在java中调用native方法就跟调用普通的java方法一样。

现在我们已经完成了java所要做的工作,让我们来看看本地方(这里以C为例)为sample类的本地方sum所提供的实现。这里需要们去解析本地方法sum的原型,还要将java类型(primitives and references)转变为C类型,因为只有这样本地C语言才能够解析使用。我们可以使用java工具 javah来完成这项工作。javah的使用方法为:假设上面的sample类的java文件为sample.java。先使用javac将其编译成sample.class,接着在命令行里输入javah sample,这样就可以产生一个叫做sample.h的头文件了,它为sample.java中的native定义了ANSI C的功能原型。以sample.h为例,你可以在里面找到native方法sum的原型如下:
JNIEXPORT jint JNICALL Java_sample_sum(JNIEnv *, jobject, jintArray, jintArray);


这里JNIEXPORT和JNICALL是两个跨平台的宏。请您注意在sum方法的参数列表中增加了两个额外的参数。第一个参数叫做接口指针(interface pointer ,细心的读者会发现我在上面已经提到过),本地方法通过它来访问JNI库中的功能方法。第二个参数jobejct 是一个指向java方调用对象的引用。您也可以把jobejct想象为java中的某个关键字。每一个由javah工具转换而生成的本地方法的原型的参数列表都要添加这两个参数,它们就是java与本地语言之间的桥梁。最后您还会注意到方法的名称和参数类型改变了。sum被映射为Java_sample_sum。“int”映射为jint,int[](Java 整数类型的数组)映射为jintArray。数据类型的映射是由javah根据java名称来转换的。

最后两步是,实现sample.h,然后把它编译成库文件。

小结
本地方法的实现的基本步骤如下:
  • 定义一个包含一个或多个native方法的java类
  • 编译你的java类。
  • 使用javah按照编译生成的class文件生成ANSI C 的头文件。
  • 实现头文件中的native方法的函数原型。
  • 将本地代码打包为共享库。
  • 现在您的程序就可以跑起来了。





参考资料:
A Brief Introduction to Java Native Interface


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics