第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参照型は、次のような階層構造になっています。
jobjectjclass(java.lang.Classオブジェクト)jstring(java.lang.Stringオブジェクト)jarray(配列)jobjectArray(オブジェクト配列)jbooleanArray(boolean配列)jbyteArray(byte配列)jcharArray(char配列)jshortArray(short配列)jintArray(int配列)jlongArray(long配列)jfloatArray(float配列)jdoubleArray(double配列)
jthrowable(java.lang.Throwableオブジェクト)
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型 |
|---|---|
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バイトで表現されます。
0xxxxxxx
バイトのうち7ビットのデータは、表現されている文字の値を示します。
null文字('\u0000')および'\u0080'から'\u07FF'の範囲の文字は、次のようにxとyの一対のバイトで表現されます。
- x:
110xxxxx - y:
10yyyyyy
このバイトは、((x & 0x1f)<< 6)+(y & 0x3f)の値で文字を表現します。
'\u0800'から'\uFFFF'の範囲の文字は、次のようにx、y、およびzの3バイトで表現されます。
- x:
1110xxxx - y:
10yyyyyy - z:
10zzzzzz
((x & 0xf)<< 12)+((y & 0x3f)<< 6)+(z & 0x3f)という値の文字がバイトで表現されます。
U+FFFFより大きなコード・ポイントを持つ文字(いわゆる補助文字)は、UTF-16表現の2つの代理コード単位を別々にエンコードすることで表現されます。 代理コード単位はそれぞれ3バイトで表現されます。 つまり、補助文字は、次のようにu、v、w、x、y、zの6バイトで表現されます。
- u:
11101101 - v:
1010vvvv - w:
10wwwwww - x:
11101101 - y:
1011yyyy - z:
10zzzzzz
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」のセクションを参照してください。