java Native方法尝试

Native方法

Java Native方法简单来说就是java调用非java代码的接口。Native方法的实现是由非java语言实现,比如c,c++。这个特征并非java所特有,很多其它的编程语言都有这一机制,比如在c++中,你可以用extern "C"告知c++编译器去调用一个C的函数。

“A native method is a Java method whose implementation is provided by non-java code.”

在定义一个native method时,并不提供实现体,我们以java.lang.Object为例,其类中有很多native方法,如getClass,hashCode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class Object {
private static native void registerNatives();
static {
registerNatives();
}
public final native Class<?> getClass();
public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
}
protected native Object clone() throws CloneNotSupportedException;
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
public final native void notify();
public final native void notifyAll();
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}

if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}

if (nanos > 0) {
timeout++;
}

wait(timeout);
}
public final void wait() throws InterruptedException {
wait(0);
}
protected void finalize() throws Throwable { }
}

JNI

Java很好,使用的人很多、应用极广,但是Java不是完美的。Java的不足体现在运行速度要比传统的C++慢上许多之外,还有Java无法直接访问到操作系统底层如硬件系统,为此Java提供了JNI来实现对于底层的访问。JNI(Java Native Interface),它是Java的SDK一部分,JNI允许Java代码使用以其他语言编写的代码和代码库,本地程序中的函数也可以调用Java层的函数,即JNI实现了Java和本地代码间的双向交互。

native方法用法和特性

标识符native可以与所有其它的java标识符连用,但是abstract除外。
一个native method方法可以返回任何java类型,包括非基本类型,而且同样可以进行异常控制。
native method的存在并不会对其他类调用这些本地方法产生任何影响,实际上调用这些方法的其他类甚至不知道它所调用的是一个本地方法。
如果一个含有本地方法的类被继承,子类会继承这个本地方法并且可以用java语言重写这个方法,同样的如果一个本地方法被fianl标识,它被继承后不能被重写。
本地方法非常有用,因为它有效地扩充了jvm。事实上,我们所写的java代码已经用到了本地方法,在sun的java的并发(多线程)的机制实现中,许多与操作系统的接触点都用到了本地方法,这使得java程序能够超越java运行时的界限。

自己实现Native方法

我使用的是CLionidea做为C++ IDE和java IDE,如果有同学使用的visual studio系列,可以查看参考博客(自己实现一个Native方法的调用)。

  1. Java代码
1
2
3
4
5
6
7
8
9
10
11
12
13
package pers.desperado.demo;

public class Demo {
static{
System.load("C:\\Users\\test\\Desktop\\demo\\Cdemo\\cmake-build-debug\\libCdemo.dll");
}

public native static void hello();

public static void main(String[] args) {
hello();
}
}

java代码很简单,申明native方法并在main函数中调用,代码块中的代码是Java加载C++的dll,这个路径一定要与第三步中生成的C++ dll路径一致。

  1. 生产.h文件

通过在Java out目录下(具体目录看下图),调用命令JNI -jni pers.desperado.demo.Demo,请注意类参数与自己命名的一致。生成后out目录下会多出一个.h文件

test

  1. C++文件

CLion通过编写makelist.txt文件来控制程序的输出形式,我们通过如下代码命令生产dll文件

1
2
3
4
5
6
# cmake_minimum_required(VERSION <specify CMake version here>)
project(Cdemo)

set(CMAKE_CXX_STANDARD 11)

add_library(Cdemo SHARED main.cpp)

(注意项目名和文件名)

将第二步生成.h文件复制到C项目文件夹下,并且将%JAVA_HOME%/include目录下的“jni.h”和%JAVA_HOME%/include/win32目录下的“jni_md.h”两个文件也复制过来
修改.h文件中的#include <jni.h>#include "jni.h"(在clion中它会自动报warning,alt+enter即可更改)

编写main.cpp

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include "pers_desperado_demo_Demo.h"

using namespace std;

JNIEXPORT void JNICALL
Java_pers_desperado_demo_Demo_hello(JNIEnv
*, jclass) {
cout << "Hello" << endl;
}

执行便会生产dll文件。

test
test

4.执行java代码

执行后便会在idea命令框中输出Hello

test

整体代码我已经放到GitHub仓库,可以自行下载尝试。指路

参考博客

什么是Native方法
自己实现一个Native方法的调用