【JVM之内存与垃圾回收篇】本地方法接口
本地方法接口
什么是本地方法
简单地讲,一个 Native Method 是一个 Java 调用非 Java 代码的接囗。一个 Native Method 是这样一个 Java 方法:该方法的实现由非 Java 语言实现,比如 C。这个特征并非 Java 所特有,很多其它的编程语言都有这一机制,比如在 C++ 中,你可以用 extern "c" 告知 C++ 编译器去调用一个 C 的函数。
"A native method is a Java method whose implementation is provided by non-java code."(本地方法是一个非 Java 的方法,它的具体实现是非 Java 代码的实现)
在定义一个 native method 时,并不提供实现体(有些像定义一个 Java interface),因为其实现体是由非 java 语言在外面实现的。
本地接口的作用是融合不同的编程语言为 Java 所用,它的初衷是融合 C/C++ 程序。
代码举例说明 Native 方法是如何编写的
/**
* 本地方法
*
* @author: Nemo
*/
public class IhaveNatives {
public native void Native1(int x);
native static public long Native2();
native synchronized private float Native3(Object o);
native void Natives(int[] ary) throws Exception;
}
需要注意的是:标识符native可以与其它java标识符连用,但是abstract除外
为什么使用 Native Method?
Java 使用起来非常方便,然而有些层次的任务用 Java 实现起来不容易,或者我们对程序的效率很在意时,问题就来了。
与 Java 环境的交互
有时 Java 应用需要与 Java 外面的环境交互,这是本地方法存在的主要原因。你可以想想 Java 需要与一些底层系统,如操作系统或某些硬件交换信息时的情况。本地方法正是这样一种交流机制:它为我们提供了一个非常简洁的接口,而且我们无需去了解 Java 应用之外的繁琐的细节。
与操作系统的交互
JVM 支持着 Java 语言本身和运行时库,它是 Java 程序赖以生存的平台,它由一个解释器(解释字节码)和一些连接到本地代码的库组成。然而不管怎样,它毕竟不是一个完整的系统,它经常依赖于一底层系统的支持。这些底层系统常常是强大的操作系统。通过使用本地方法,我们得以用 Java 实现了 jre 的与底层系统的交互,甚至 JVM 的一些部分就是用 C 写的。还有,如果我们要使用一些 Java 语言本身没有提供封装的操作系统的特性时,我们也需要使用本地方法。
Sun's Java
Sun 的解释器是用 C 实现的,这使得它能像一些普通的 C 一样与外部交互。jre 大部分是用 Java 实现的,它也通过一些本地方法与外界交互。例如:类 java.lang.Thread 的 setPriority()
方法是用 Java 实现的,但是它实现调用的是该类里的本地方法 setPriority()
。这个本地方法是用 C 实现的,并被植入 JVM 内部,在 Windows 95 的平台上,这个本地方法最终将调用 Win32 setPriority() API。这是一个本地方法的具体实现由 JVM 直接提供,更多的情况是本地方法由外部的动态链接库(external dynamic link library)提供,然后被 JVW 调用。
注意:标识符 native 可以与所有其他的 Java 标识符连用,但是 abstract 除外。
现状
目前该方法使用的越来越少了,除非是与硬件有关的应用,比如通过 Java 程序驱动打印机或者 Java 系统管理生产设备,在企业级应用中已经比较少见。因为现在的异构领域间的通信很发达,比如可以使用 Socket 通信,也可以使用 Web Service 等等,不多做介绍。
Java如何调用C语言程序,JNI技术
Java为什么要调用C语言编写的程序
因为涉及操作系统底层的事件,Java是处理不了的,例如用户上传一个视频文件,需要后台给视频加上水印,或者后台分离视频流和音频流,这个事Java就做不了,只能交给C语言去处理,然后Java调用C语言的接口。
使用Java如何去调用C语言的接口呢?
使用Java的JNI技术。
具体调用步骤
CentOS7环境下
首先创建Java文件 HelloJni.java ,并创建native方法
package com.hongyu.jni;
public class HelloMyJni{
public native void helloWorld(); // 注意,这个native方法就是调用C语言接口用的
static{
System.loadLibrary("hello"); // 这行是调用动态链接库
}
public static void main(String[] args){
new HelloMyJni().helloWorld();
}
}
编译Java文件并生成java头文件
javac -d . HelloJni.java // 生成class文件
javah -jni com.hongyu.jni.HelloJni // 生成java头文件 com_hongyu_jni_HelloJni.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_hongyu_jni_HelloJni */
#ifndef _Included_com_hongyu_jni_HelloJni
#define _Included_com_hongyu_jni_HelloJni
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_hongyu_jni_HelloJni
* Method: helloWorld
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_hongyu_jni_HelloJni_helloWorld
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
创建C语言文件,HelloWorld.c
#include "jni.h"
#include "com_hongyu_jni_HelloJni.h"
#include <stdio.h>
#include <stdlib.h>
JNIEXPORT void JNICALL Java_com_hongyu_jni_HelloJni_helloWorld(JNIEnv * env, jobject obj)
{
printf("Hello World!\n");
}
生成动态链接库文件 libhello.so
#gcc -Wall -fPIC -c HelloWorld.c -I ./ -I $JAVA_HOME/include/linux/ -I $JAVA_HOME/include/
#gcc -Wall -rdynamic -shared -o libhello.so HelloWorld.o
设置动态链接库文件的目录
打开文件
vi ~/.bash_profile
修改文件:
export JAVA_HOME=/home/jdk1.8.0_161
export PATH=$JAVA_HOME/bin:$PATH
export LD_LIBRARY_PATH=/home/lib:$LD_LIBRARY_PATH
刷新文件:
source ~/.bash_profile
把刚才生成的so文件拷贝到/home/lib下,然后执行class文件
java com.hongyu.jni.HelloJni
大功告成!Java成功调用了C语言编写的逻辑
笔者将不定期更新【考研或就业】的专业相关知识以及自身理解,希望大家能【关注】我。
如果觉得对您有用,请点击左下角的【点赞】按钮,给我一些鼓励,谢谢!
如果有更好的理解或建议,请在【评论】中写出,我会及时修改,谢谢啦!
本文来自博客园,作者:Nemo&
转载请注明原文链接:https://www.cnblogs.com/blknemo/p/13295824.html