第3章: JNIの型とデータ構造

この章では、JNIがどのようにJavaの型をネイティブCの型にマッピングするかを解説します。

この章では次のトピックについて説明します。

プリミティブ型

次の表は、Javaのプリミティブ型およびそれらのマシン依存のネイティブ型との対応について説明しています。

プリミティブ型とネイティブ型
Java型 ネイティブ型 説明
boolean jboolean unsigned 8ビット
byte jbyte signed 8ビット
char jchar unsigned 16ビット
short jshort signed 16ビット
int jint signed 32ビット
long jlong signed 64ビット
float jfloat 32ビット
double jdouble 64ビット
void void 適用外

次の定義は、利便性のため提供されています。

#define JNI_FALSE  0
#define JNI_TRUE   1

jsize整数型は、基本的なインデックスおよびサイズを記述するために使用されます。

typedef jint jsize;

参照型

JNIには、各種のJavaオブジェクトに対応する多くの参照型が含まれています。 JNI参照型は、次のような階層構造になっています。

Cでは、その他すべてのJNI参照型は、jobjectと同じように定義されています。 たとえば、

typedef jobject jclass;

C++では、JNIはダミー・クラスのセットを導入して、サブタイプ関係を強制します。 たとえば、

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

フィールドとメソッドID

フィールドとメソッドIDは、次のように正規のCポインタ型です。

struct _jfieldID;              /* opaque structure */
typedef struct _jfieldID *jfieldID;   /* field IDs */

struct _jmethodID;              /* opaque structure */
typedef struct _jmethodID *jmethodID; /* method IDs */

値の型

jvalue共用体型は、引数配列で要素型として使用されます。 これは次のように宣言されます。

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

型のシグニチャ

JNIは、Java VMの型シグニチャ表現を使用します。 次の表は、これらの型シグネチャを示しています。

Java VM型のシグネチャ
型シグニチャ Java型
Z boolean
B byte
C char
S short
I int
J long
F float
D double
L fully-qualified-class ; 完全修飾のクラス
[タイプ type []
( arg-types ) ret-type メソッドの型

たとえば、次のJavaメソッドには、

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

次のような型のシグニチャがあります。

(ILjava/lang/String;[I)J

変更後のUTF-8文字列

JNIは変更後のUTF-8文字列を使用して各種の文字列型を表現します。 変更後のUTF-8文字列はJava VMによって使用されるものと同じです。 変更後のUTF-8文字列は、1文字につき1バイトだけを使用してnull以外のASCII文字だけが含まれる文字シーケンスが表現できるようにエンコードされていますが、Unicode文字もすべて表現できます。

次のように、\u0001から\u007Fの範囲のすべての文字が1バイトで表現されます。

バイトのうち7ビットのデータは、表現されている文字の値を示します。

null文字('\u0000')および'\u0080'から'\u07FF'の範囲の文字は、次のようにxとyの一対のバイトで表現されます。

このバイトは、((x & 0x1f)<< 6)+(y & 0x3f)の値で文字を表現します。

'\u0800'から'\uFFFF'の範囲の文字は、次のようにx、y、およびzの3バイトで表現されます。

((x & 0xf)<< 12)+((y & 0x3f)<< 6)+(z & 0x3f)という値の文字がバイトで表現されます。

U+FFFFより大きなコード・ポイントを持つ文字(いわゆる補助文字)は、UTF-16表現の2つの代理コード単位を別々にエンコードすることで表現されます。 代理コード単位はそれぞれ3バイトで表現されます。 つまり、補助文字は、次のようにuvwxyzの6バイトで表現されます。

0x10000+((v&0x0f)<<16)+((w&0x3f)<<10)+(y&0x0f)<<6)+(z&0x3f)という値の文字は、6バイトで表現されます。

マルチバイト文字のバイトは、classファイルにビッグ・エンディアン順(高位バイトが先)に格納されています。

この形式と標準UTF-8形式とでは、2つの相違点があります。 第一は、null文字(char)0が、1バイト形式でなく2バイト形式でエンコードされていることです。 これは、変更後のUTF-8文字列にnullが組み込まれないことを意味します。 第二は、標準UTF-8の1バイト、2バイト、および3バイト形式だけが使用されていることです。 Java VMは、標準UTF-8の4バイト形式を認識せず、2 x 3バイト形式を使用します。

標準UTF-8形式に関する詳細は、『The Unicode Standard, Version 4.0』の「3.9 Unicode Encoding Forms」のセクションを参照してください。