Android_JNI编程入门

最权威的文档请见JNI

一、JNI概述

  在某些情况下,单独使用Java编程无法满足开发者的需求,这时可以使用JNI(Java Native Interface)来处理。常见的需要使用JNI的场景有:

(1)标准Java类库不支持应用程序所需的平台相关特性。
(2)存在其他语言编写的库,并且希望通过JNI使Java代码能够使用该库。
(3)用低级语言(如汇编)实现一小部分时间关键型代码。

  通过JNI编程,可以使用native methods做到:

(1)创建、检查和更新Java对象(包括数组和字符串)。
(2)调用Java方法。
(3)捕获并抛出异常。
(4)加载类并获取类信息。
(5)执行运行时类型检查。

二、JNI类型对应

2.1 基础类型

在这里插入图片描述

2.2 引用类型

在这里插入图片描述
在C++中:

class _jobject {};
class _jclass : public _jobject {};
// ...
typedef _jobject *jobject;
typedef _jclass *jclass;

2.3 值类型

typedef union jvalue {
    jboolean z;
    jbyte    b;
    jchar    c;
    jshort   s;
    jint     i;
    jlong    j;
    jfloat   f;
    jdouble  d;
    jobject  l;
} jvalue;

2.4 类型签名

在这里插入图片描述
对于以下Java方法:

long f (int n, String s, int[] arr);

具有如下签名(signature):

(ILjava/lang/String;[I)J

三、JNI函数操作

JNI方法列表请见:Interface Function Table

(1)其中有对象操作方法如:

jobject NewObjectV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);

其中参数:
env: JNI 接口指针,不能为null
clazz: Java类对象的引用,不能为null
methodID: 构造函数的MethodID,可以通过GetMethodID()获得

(2)其中有对象Fileld 访问方法如:

jfieldID GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig);

其中参数:
env: JNI 接口指针,不能为null
clazz: Java类对象,不能为null
name: 字段名的UTF-8 string, 不能为null
sig: 字段签名的UTF-8 string, 不能为null

…方法较多就不再继续罗列。

四、native方法注册

JVM有两种方法来查找native方法并将其与Java代码链接。第一种方法是以特定的命名方式命名native 函数,以便JVM能够找到它。另一种方法是使用JNI RegisterNatives()方法,RegisterNatives()使用作为参数传递的类注册本机方法。通过使用这种方法,我们可以随意命名C++函数。java.lang.Object的registerNatives()方法使用了第二种方法。让我们看看C语言中OpenJDK 8中java.lang.Object的registerNatives()方法实现:

static JNINativeMethod methods[] = {
    {"hashCode",    "()I",                    (void *)&JVM_IHashCode},
    {"wait",        "(J)V",                   (void *)&JVM_MonitorWait},
    {"notify",      "()V",                    (void *)&JVM_MonitorNotify},
    {"notifyAll",   "()V",                    (void *)&JVM_MonitorNotifyAll},
    {"clone",       "()Ljava/lang/Object;",   (void *)&JVM_Clone},
};

JNIEXPORT void JNICALL
Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
{
    (*env)->RegisterNatives(env, cls,
                            methods, sizeof(methods)/sizeof(methods[0]));
}

五、使用JNI例子

public class RegisterNativesHelloWorldJNI {

    public native void register();
    public native String sayHello();

    public static void main(String[] args) {
        RegisterNativesHelloWorldJNI helloWorldJNI = new RegisterNativesHelloWorldJNI();
        helloWorldJNI.register();
        helloWorldJNI.sayHello();
    }
}
//c++注册实现
static JNINativeMethod methods[] = {
  {"sayHello", "()Ljava/lang/String;", (void*) &hello },
};

JNIEXPORT void JNICALL Java_com_baeldung_jni_RegisterNativesHelloWorldJNI_register (JNIEnv* env, jobject thsObject) {
    jclass clazz = env->FindClass("com/baeldung/jni/RegisterNativesHelloWorldJNI");

    (env)->RegisterNatives(clazz, methods, sizeof(methods)/sizeof(methods[0]));
}

JNIEXPORT jstring JNICALL hello (JNIEnv* env, jobject thisObject) {
    std::string hello = "Hello from registered native C++ !!";
    std::cout << hello << std::endl;
    return env->NewStringUTF(hello.c_str());
}

打印:

Hello from registered native C++ !!
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值