- PR -

JNIにおける基本型の二次元配列について

1
投稿者投稿内容
いつはし
会議室デビュー日: 2006/10/30
投稿数: 12
投稿日時: 2007-11-10 16:21
JNIにおけるJavaの基本型の二次元配列の取り扱いについて悩んでいます。
具体的には、JNIのネイティブソースの中で、jint[][]を新規作成してJavaオブジェクトのメソッドに引数として渡したいと考えています。
しかし、JNIにおけるjint[][]の新規作成方法、またはそれに代わる二次元配列の取り扱い方法がわかりません。

下記のような手順でObject配列にint配列を代入することで実現しようとしたのですが、
実行するとJNI上ではエラーにならないのですが、Java側でjava.lang.ClassCastExceptionが投げられ、
Object配列がint配列にキャストできない、といったメッセージが表示されます。

---
jclass obj = env->FindClass("java/lang/Object");
jobjectArray arr = env->NewObjectArray(num, obj, NULL);
for (i = 0; i < n; i++) {
 jintArray is = env->NewIntArray(num);
 jboolean isCopy = JNI_FALSE;
 jint* p_is = env->GetIntArrayElements(is, &isCopy);
 env->SetObjectArrayElement(arr, i, is);
for (j = 0; j < num; j++) {
//配列に値を設定
}
}
env->CallVoidMethod(objClass, setTwoIntArray, arr);
---

データをVectorとして扱う方法も考えていますが、何かよい方法はないでしょうか。
よろしくお願いします。
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-11-10 17:39
引用:

いつはしさんの書き込み (2007-11-10 16:21) より:
jclass obj = env->FindClass("java/lang/Object");


jclass obj = env->FindClass("[I");
とするとどうなりますか?
いつはし
会議室デビュー日: 2006/10/30
投稿数: 12
投稿日時: 2007-11-10 18:56
いつはしです。

該当箇所を、jclass obj = env->FindClass("[I"); としました。
しかし、env->NewObjectArray()を呼んだ時点で落ちてしまいました。

Pure JavaでObject[]にint[]を代入した後、それをint[][]として扱う手段があれば、それをJNIでも同様に実装すればいいのかとも思いますが、不勉強なためそれもわからず…。

引き続きよろしくお願いします。
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2007-11-12 11:15
Array.newInstance(int[].class, num) を使用するとうまくいくかもしれません。

コード:

	jclass intClass = env->FindClass("[I");
	jclass ArrayClass = env->FindClass("java/lang/reflect/Array");
	jmethodID ArrayClass_newInstance = env->GetMethodID(ArrayClass, "newInstance", "(Ljava/lang/Class;I)Ljava/lang/Object;");
	jobjectArray arr = (jobjectArray)env->CallStaticObjectMethod(ArrayClass, ArrayClass_newInstance, intClass, num);



上記 JNI のコードは動作確認していませんが、以下の Java コードでは Object を int[][] にキャストできることを確認しました。

コード:

	Object obj = Array.newInstance(int[].class, 10);
	int[][] arr = (int[][])obj;


Tdnr_Sym
ぬし
会議室デビュー日: 2005/09/13
投稿数: 464
お住まい・勤務地: 明石・神戸
投稿日時: 2007-11-12 12:55
こんにちは。

汚いですがサンプルコードを作ってみました。
一応動作確認済みです。
参考までに。

Javaコード
コード:
class Test{
	static {
	    System.loadLibrary("Test");
  	}
	
	private native void nativeMethod();
	
	public static void main(String args[]) {
    	Test t = new Test();
    	t.nativeMethod();
  }
  
  private void printIntArray(int[][] arr) {
  	  for (int i = 0; i < arr.length; i++) {
  	  	  for (int j = 0; j < arr[i].length; j++) {
  	  	  	  if (j != 0) {
	  	  	  	  System.out.print(",");
  	  	  	  }
  	  	  	  System.out.print(arr[i][j]);
  	  	  }
  	  	  System.out.println();
  	  }
  }
}



C++ JNIコード
コード:
JNIEXPORT void JNICALL Java_Test_nativeMethod__(JNIEnv* env, jobject obj)
{
	jsize N1 = 5;
	jsize N2 = 10;

	jclass clsAI = env->FindClass("java/lang/Object");
	//jclass clsAI = env->FindClass("[I"); 		こっちでもOK

	jobjectArray arr = env->NewObjectArray(N1, clsAI, NULL); 
	for (int i = 0; i < N1; i++) { 
		jintArray is = env->NewIntArray(N2); 
		jboolean isCopy = JNI_FALSE; 
		jint* p_is = env->GetIntArrayElements(is, &isCopy); 
		env->SetObjectArrayElement(arr, i, is); 
		for (int j = 0; j < N2; j++) { 
			p_is[j] = i + j;
		} 
		env->ReleaseIntArrayElements(is, p_is, 0);
	} 

	jclass cls = env->GetObjectClass(obj);
	jmethodID mid = env->GetMethodID(cls, "printIntArray", "([[I)V");
	env->CallVoidMethod(obj, mid, arr); 
}

いつはし
会議室デビュー日: 2006/10/30
投稿数: 12
投稿日時: 2007-11-12 18:01
すみません、今立込んでますのできちんと検証出来ない状態なのですが…

Tdnr_Symさんのコードは、見たところ私が初めに試した方法と同じ処理に見えます。
そのときは、JNIコード中でJavaオブジェクトに二次元配列を設定し、サーブレットに処理が戻るまでは問題なかったのですが、ネットワーク通信後にAppletがオブジェクトを受け取った辺りでClassCastExceptionが投げられてしまいました。
(何か見逃している単純なミスがあるのかもしれませんが。)

追って動作確認後、結果を報告いたします。ありがとうございました。
1

スキルアップ/キャリアアップ(JOB@IT)