java native调用



Object

  • registerNatives()
  • getClass()
  • hashCode()
  • equals()
  • clone()
  • toString()
  • notify()
  • notifyAll()
  • wait(long timeout)
  • wait(long timeout, int nanos)
  • wait()
  • finalize()

Object就这几个方法,其中除equals和toString,其他都是native方法.

本文就以Object来探讨下java的native,源码基于openjdk7

Object native方法的声明在openjdk/jdk/src/share/native/java/lang/Object.c中

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},
};

JNINativeMethod的结构体如下:

typedef struct {
    char *name;
    char *signature;
    void *fnPtr;
} JNINativeMethod;
  • name Object的方法名称
  • signature 方法签名
  • fnPtr native实现的函数指针

对应的native实现在openjdk/hotspot/src/share/vm/prims/jvm.cpp

hashCode():

JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle))
  JVMWrapper("JVM_IHashCode");
  // as implemented in the classic virtual machine; return 0 if object is NULL
  return handle == NULL ? 0 : ObjectSynchronizer::FastHashCode (THREAD, JNIHandles::resolve_non_null(handle)) ;
JVM_END

wait():

JVM_ENTRY(void, JVM_MonitorWait(JNIEnv* env, jobject handle, jlong ms))
  JVMWrapper("JVM_MonitorWait");
  Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
  assert(obj->is_instance() || obj->is_array(), "JVM_MonitorWait must apply to an object");
  JavaThreadInObjectWaitState jtiows(thread, ms != 0);
  if (JvmtiExport::should_post_monitor_wait()) {
    JvmtiExport::post_monitor_wait((JavaThread *)THREAD, (oop)obj(), ms);
  }
  ObjectSynchronizer::wait(obj, ms, THREAD);
JVM_END

JVM_ENTRY的结构体定义在openjdk/hotspot/src/share/vm/runtime/interfaceSupport.hpp

#define JVM_ENTRY(result_type, header)                               \
extern "C" {                                                         \
  result_type JNICALL header {                                       \
    JavaThread* thread=JavaThread::thread_from_jni_environment(env); \
    ThreadInVMfromNative __tiv(thread);                              \
    debug_only(VMNativeEntryWrapper __vew;)                          \
    VM_ENTRY_BASE(result_type, header, thread)

JVM_END

#define JVM_END } }

Object

  • registerNatives()
  • getClass()
  • hashCode()
  • equals()
  • clone()
  • toString()
  • notify()
  • notifyAll()
  • wait(long timeout)
  • wait(long timeout, int nanos)
  • wait()
  • finalize()

Object就这几个方法,其中除equals和toString,其他都是native方法.

本文就以Object来探讨下java的native,源码基于openjdk7

Object native方法的声明在openjdk/jdk/src/share/native/java/lang/Object.c中

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},
};

JNINativeMethod的结构体如下:

typedef struct {
    char *name;
    char *signature;
    void *fnPtr;
} JNINativeMethod;
  • name Object的方法名称
  • signature 方法签名
  • fnPtr native实现的函数指针

对应的native实现在openjdk/hotspot/src/share/vm/prims/jvm.cpp

hashCode():

JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle))
  JVMWrapper("JVM_IHashCode");
  // as implemented in the classic virtual machine; return 0 if object is NULL
  return handle == NULL ? 0 : ObjectSynchronizer::FastHashCode (THREAD, JNIHandles::resolve_non_null(handle)) ;
JVM_END

wait():

JVM_ENTRY(void, JVM_MonitorWait(JNIEnv* env, jobject handle, jlong ms))
  JVMWrapper("JVM_MonitorWait");
  Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
  assert(obj->is_instance() || obj->is_array(), "JVM_MonitorWait must apply to an object");
  JavaThreadInObjectWaitState jtiows(thread, ms != 0);
  if (JvmtiExport::should_post_monitor_wait()) {
    JvmtiExport::post_monitor_wait((JavaThread *)THREAD, (oop)obj(), ms);
  }
  ObjectSynchronizer::wait(obj, ms, THREAD);
JVM_END

JVM_ENTRY的结构体定义在openjdk/hotspot/src/share/vm/runtime/interfaceSupport.hpp

#define JVM_ENTRY(result_type, header)                               \
extern "C" {                                                         \
  result_type JNICALL header {                                       \
    JavaThread* thread=JavaThread::thread_from_jni_environment(env); \
    ThreadInVMfromNative __tiv(thread);                              \
    debug_only(VMNativeEntryWrapper __vew;)                          \
    VM_ENTRY_BASE(result_type, header, thread)

JVM_END

#define JVM_END } }
好的,这是一个比较复杂的JNI项目,需要注意的地方比较多,我会尽量详细地给出代码和说明。 首先,我们需要在VS中创建一个空的C++项目,命名为"JNIproject",然后在项目中添加两个cpp文件,分别命名为"JNItest.cpp"和"JNIfunction.cpp"。 在"JNIfunction.cpp"中,我们写一些C++函数,这些函数最终会被Java调用。以下是一个简单的例子: ```cpp #include <stdio.h> #include "JNIfunction.h" JNIEXPORT void JNICALL Java_com_example_JNItest_print(JNIEnv *env, jobject obj, jstring str) { const char *s = env->GetStringUTFChars(str, NULL); printf("%s\n", s); env->ReleaseStringUTFChars(str, s); } JNIEXPORT jstring JNICALL Java_com_example_JNItest_reverse(JNIEnv *env, jobject obj, jstring str) { const char *s = env->GetStringUTFChars(str, NULL); char *r = new char[strlen(s) + 1]; for (int i = 0; i < strlen(s); i++) { r[i] = s[strlen(s) - i - 1]; } r[strlen(s)] = '\0'; jstring result = env->NewStringUTF(r); delete[] r; env->ReleaseStringUTFChars(str, s); return result; } ``` 这里我们定义了两个函数,一个是"print"函数,它接收一个字符串并打印出来;另一个是"reverse"函数,它接收一个字符串并返回其反转后的结果。 然后我们需要在"JNIfunction.h"中声明这些函数: ```cpp #ifndef _Included_JNIfunction #define _Included_JNIfunction #include <jni.h> #ifdef __cplusplus extern "C" { #endif JNIEXPORT void JNICALL Java_com_example_JNItest_print(JNIEnv *, jobject, jstring); JNIEXPORT jstring JNICALL Java_com_example_JNItest_reverse(JNIEnv *, jobject, jstring); #ifdef __cplusplus } #endif #endif ``` 接下来我们需要在"JNItest.cpp"中实现Java调用C++层的接口: ```cpp #include <jni.h> #include "JNIfunction.h" JNIEXPORT void JNICALL Java_com_example_JNItest_print(JNIEnv *env, jobject obj, jstring str) { jclass cls = env->GetObjectClass(obj); jmethodID mid = env->GetMethodID(cls, "printString", "(Ljava/lang/String;)V"); if (mid == NULL) { return; } env->CallVoidMethod(obj, mid, str); } JNIEXPORT jstring JNICALL Java_com_example_JNItest_reverse(JNIEnv *env, jobject obj, jstring str) { jclass cls = env->GetObjectClass(obj); jmethodID mid = env->GetMethodID(cls, "reverseString", "(Ljava/lang/String;)Ljava/lang/String;"); if (mid == NULL) { return NULL; } return (jstring) env->CallObjectMethod(obj, mid, str); } JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv *env; if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { return -1; } jclass cls = env->FindClass("com/example/JNItest"); if (cls == NULL) { return -1; } static JNINativeMethod methods[] = { {"print", "(Ljava/lang/String;)V", (void *) Java_com_example_JNItest_print}, {"reverse", "(Ljava/lang/String;)Ljava/lang/String;", (void *) Java_com_example_JNItest_reverse} }; jint ret = env->RegisterNatives(cls, methods, sizeof(methods) / sizeof(methods[0])); if (ret != JNI_OK) { return -1; } return JNI_VERSION_1_6; } ``` 这里我们实现了Java调用C++层的"print"和"reverse"函数,并在"JNI_OnLoad"函数中注册这些函数。 最后,我们需要在VS中设置项目的属性,以便将其编译成.so库。具体步骤如下: 1. 右键点击"JNIproject"项目,选择"属性"。 2. 在"常规"选项卡中,将"配置类型"设置为"动态库(.dll)",将"目标扩展名"设置为".so"。 3. 在"C/C++"选项卡中,将"附加包含目录"设置为JDK的include目录,例如:"C:\Program Files\Java\jdk1.8.0_271\include"。 4. 在"C/C++"选项卡中,将"附加库目录"设置为JDK的lib目录,例如:"C:\Program Files\Java\jdk1.8.0_271\lib"。 5. 在"C/C++"选项卡中,将"代码生成"选项卡中的"运行库"设置为"多线程DLL(/MD)"。 6. 在"链接器"选项卡中,将"附加依赖项"设置为"jvm.lib"。 7. 在"链接器"选项卡中,将"输出文件"设置为"JNItest.so"。 现在我们可以编译项目了。编译完成后,我们可以在"JNIproject\Debug"目录下找到生成的JNItest.so库。 最后,我们需要在Linux下编写Java代码,调用这个.so库。以下是一个简单的例子: ```java package com.example; public class JNItest { static { System.loadLibrary("JNItest"); } private native void print(String str); private native String reverse(String str); public static void main(String[] args) { JNItest jni = new JNItest(); jni.print("Hello JNI"); String rev = jni.reverse("Hello JNI"); System.out.println(rev); } } ``` 这里我们通过静态代码块加载JNItest.so库,并实现了"print"和"reverse"函数的Java层接口。 希望这个例子能够帮助你理解如何在VS中创建含有多个cpp文件组成的复杂JNI项目,并编译成.so库,最终由Linux下的Java native调用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值