| 目次 | 前の項目 | 次の項目 | Java Native Interface 仕様 | 
この呼び出し API により、ソフトウェアベンダーは Java VM* を任意のネイティブアプリケーションにロードできるようになります。 そのベンダーの提供する Java が実行可能なアプリケーションは、Java VM ソースコードにリンクする必要がありません。
この章では、呼び出し API の概要の説明から始めます。 それ以降は、すべての呼び出し API 関数のリファレンスページです。
Java VM の組み込み機能を向上させるため、JDK 1.1.2 の呼び出し API はいくつかの細かな点が拡張されています。
Main.test と呼ばれる static メソッドを起動します。 明確にするために、エラーチェックを省略しました。
        #include <jni.h>       /* where everything is defined */
        ...
        JavaVM *jvm;       /* denotes a Java VM */
        JNIEnv *env;       /* pointer to native method interface */
        JDK1_1InitArgs vm_args; /* JDK 1.1 VM initialization arguments */
        vm_args.version = 0x00010001; /* New in 1.1.2: VM version */
        /* Get the default initialization arguments and set the class
         * path */
        JNI_GetDefaultJavaVMInitArgs(&vm_args);
        vm_args.classpath = ...;
        /* load and initialize a Java VM, return a JNI interface
         * pointer in env */
        JNI_CreateJavaVM(&jvm, &env, &vm_args);
        /* invoke the Main.test method using the JNI */
        jclass cls = env->FindClass("Main");
        jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V");
        env->CallStaticVoidMethod(cls, mid, 100);
        /* We are done. */ */
        jvm->DestroyJavaVM();
 この例では、API の 3 つの関数を使用しています。 呼び出し API はネイティブアプリケーションが JNI インタフェースポインタを使用して VM 機能にアクセスできるようにします。 この設計は Netscape の JRI 埋め込みインタフェースと同様です。
JNI_CreateJavaVM() 関数は Java VM をロードして初期化し、JNI インタフェースポインタにポインタを返します。 JNI_CreateJavaVM() を呼び出したスレッドは、「メインスレッド」とみなされます。
JNIEnv) は、現在のスレッドでのみ有効です。 別のスレッドが Java VM にアクセスする必要がある場合、これは最初に AttachCurrentThread() を呼び出し、それ自体を VM に接続し JNI インタフェースポインタを取得する必要があります。 一度 VM に接続されると、ネイティブスレッドはネイティブメソッド内で実行中の普通の Java スレッドのように機能します。 ネイティブスレッドは、それ自体を分離するために DetachCurrentThread() を呼び出すまで VM に接続されたままになります。
DestroyJavaVM() を呼び出す必要があります。
VM は、メインスレッドが唯一のユーザスレッドになるまで待機し、そのあとアンロードを実行します。 ユーザスレッドには、Java スレッドおよび接続されたネイティブスレッドの両方があります。 この制限は、Java スレッドまたは接続されたネイティブスレッドがロック、ウィンドウなどのシステムリソースを保持している可能性があるために存在します。 VM は、自動的にこれらのリソースを解放することはできません。 VM がアンロードされているときに、メインスレッドを唯一の実行中のスレッドであると制限することで、任意のスレッドが保持するシステムリソースを解放する負荷はプログラマに課せられます。
 Java VM によって異なる初期化引数が必要とされる可能性があります。 現在および将来のすべての Java VM に対し、適切な、標準の初期化構造体を提供することは困難です。 妥協策として、最初のフィールド (version) を初期化構造体の内容識別用に予約しておきます。 JDK 1.1.2 を組み込んだネイティブアプリケーションは、このバージョンフィールドを 0x00010001 に設定する必要があります。 実装によっては、JDK のサポートする初期化引数のいくつかを無視することを選択するかもしれませんが、VM 実装では、JDK と同じ初期化構造体を使うことをお勧めします。
 バージョン番号 0x80000000 から 0xFFFFFFFF は予約されているので、VM 実装で使用できません。
次のコードは、JDK 1.1.2 で Java VM の初期化に使われる構造体を示します。
    typedef struct JavaVMInitArgs {
       /* The first two fields were reserved in JDK 1.1, and
          formally introduced in JDK 1.1.2. */
       /* Java VM version */
        jint version;
       /* System properties. */
        char **properties;
       /* whether to check the Java source files are newer than
        * compiled class files. */ */
        jint checkSource;
       /* maximum native stack size of Java-created threads. */ */
        jint nativeStackSize;
       /* maximum Java stack size. */ */
        jint javaStackSize;
       /* initial heap size. */ */
        jint minHeapSize;
       /* maximum heap size. */ */
        jint maxHeapSize;
       /* controls whether Java byte code should be verified:
        * 0 -- none, 1 -- remotely loaded code, 2 -- all code. */
        jint verifyMode;
       /* the local directory path for class loading. */
        const char *classpath;
       /* a hook for a function that redirects all VM messages. */
        jint (*vfprintf)(FILE *fp, const char *format,
                         va_list args);
       /* a VM exit hook. */
        void (*exit)(jint code);
       /* a VM abort hook. */
        void (*abort)();
       /* whether to enable class GC. */
        jint enableClassGC;
       /* whether GC messages will appear. */
        jint enableVerboseGC;
       /* whether asynchronous GC is allowed. */
        jint disableAsyncGC;
       /* Three reserved fields. */
        jint reserved0;
        jint reserved1;
        jint reserved2;
    } JDK1_1InitArgs;
 JDK 1.1.2 では、初期化構造体が提供するフックにより、ネイティブアプリケーションは VM メッセージをリダイレクトすることができ、VM の終了を制御することができるようになります。
次に示す構造体は、ネイティブスレッドが JDK 1.1.2 の Java VM に接続するとき、引数として渡されます。実際、ネイティブスレッドが JDK 1.1.2 へ接続するために引数は必要ありません。JDK1_1AttachArgs 構造体は、空の構造体を許さない C コンパイラ用の埋め込みスロットだけから成ります。
    typedef struct JDK1_1AttachArgs {
       /*
        * JDK 1.1 does not need any arguments to attach a
        * native thread. The padding is here to satisfy the C
        * compiler which does not permit empty structures.
        */
        void *__padding;
    } JDK1_1AttachArgs;
JavaVM 型は呼び出し API 関数テーブルのポインタです。 次のコード例では、この関数テーブルを示します。
    typedef const struct JNIInvokeInterface *JavaVM;
    const struct JNIInvokeInterface ... = {
        null,
        null,
        null,
        DestroyJavaVM,
        AttachCurrentThread,
        DetachCurrentThread,
    };
 次の 3 つの呼び出し API 関数に注意してください。JNI_GetDefaultJavaVMInitArgs()、JNI_GetCreatedJavaVMs()、および JNI_CreateJavaVM() は、Java VM 関数ではありません。 これらの関数は既存の JavaVM 構造体がなくても使用することができます。
jint JNI_GetDefaultJavaVMInitArgs(void *vm_args); 
Java VM のデフォルト構成を返します。 この関数を呼び出す前に、ネイティブコードは、vm_args->version フィールドを、VM にサポートさせたい JNI バージョンに設定しておかなければなりません。 JDK 1.1.2 では、vm_args->version は、0x00010001 に設定する必要があります。
JDK 1.1 では、ネイティブコードでバージョンフィールドを設定する必要はありませんでした。 下位互換のため、バージョンフィールドが設定されていない場合は、JDK 1.1.2 は、要求されたバージョンが 0x00010001 だと想定します。 JDK の将来のバージョンでは、バージョンフィールドを適切な値に設定する必要があります。
この関数から復帰すると、vm_args->version は、VM がサポートする実際の JNI バージョンに設定されます。
vm_args: デフォルト引数が入る VM 固有の初期化構造体へのポインタ
jint JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen,
 jsize *nVMs); 作成された Java VM をすべて返します。 VM へのポインタは、作成された順にバッファ vmBuf に書き込まれます。 しかし、エントリの bufLen 番号しか書き込みません。 作成された VM の全体数は、*nVM で返します。
JDK 1.1 は 1 つのプロセスで、1 つの VM しかサポートしません。
vmBuf: VM 構造体が配置されるバッファへのポインタ
jint JNI_CreateJavaVM(JavaVM **p_vm, JNIEnv **p_env,
 void *vm_args);  ロードして、Java VM を初期化します。 現在のスレッドがメインスレッドになります。 env 引数を、メインスレッドの JNI インタフェースポインタへ設定します。
 JDK は 1 つのプロセスで、1 つの VM しかサポートしません。 vm_args のバージョンフィールドは、0x00010001 に設定する必要があります。
p_vm: 結果の VM 構造体が配置される位置へのポインタ
 p_env: メインスレッドの JNI インタフェースポインタが配置される位置へのポインタ
jint DestroyJavaVM(JavaVM *vm);  Java VM をアンロードし、そのリソースを回復します。 メインスレッドだけが VM をアンロードできます。 メインスレッドは、DestroyJavaVM() を呼び出すとき、唯一残ったユーザスレッドでなければなりません。
vm: 破壊される Java VM
JDK 1.1.2 は VM のアンロードをサポートしません。
jint AttachCurrentThread(JavaVM *vm, JNIEnv **p_env,
 void *thr_args); 現在のスレッドを Java VM へ接続します。 JNIEnv 引数で JNI インタフェースポインタを返します。
ネイティブスレッドを 2 つの Java VM へ同時に接続することはできません。
スレッドが VM に接続されている場合、コンテキストクラスのローダは、ブートストラップローダです。
vm: 現在のスレッドが接続される VM
 p_env: 現在のスレッドの JNI インタフェースポインタが配置される位置へのポインタ
jint DetachCurrentThread(JavaVM *vm); Java VM から現在のスレッドを分離します。 このスレッドが保持する Java モニターはすべて解放されます。 このスレッドが終了するのを待つ Java スレッドすべてに、通知が行われます。
 Java VM を作成するスレッドであるメインスレッドを、VM から分離することができません。 その代わり、VM 全体をアンロードするために、メインスレッドは JNI_DestroyJavaVM() を呼び出す必要があります。
vm: 現在のスレッドが分離される VM
*Web サイトでも使用していますが、「Java VM」とは、Java プラットフォームの仮想マシンのことです。
 Java Native Interface 仕様 (1997 年 3 月 15 日に dkramer によって生成された HTML) 
 Copyright © 1996, 1997 Sun Microsystems, Inc. All rights reserved 
 コメントや訂正は、jni@java.sun.com までお送りください。