ファイヤープロジェクト
メソッドを呼び出す
2003-07-20T15:13+09:00   matsu
ネイティブコードからクラスやオブジェクトのメソッドを呼び出す.
メソッドを呼び出す時の流れは,フィールドの取得や設定とそんなに変わらない.以下にその流れを示す.
インスタンスメソッドの場合スタティックメソッドの場合
必要があればGetObjectClassでjclassを取得する
GetMethodIDでメソッドIDを取得GetStaticMethodIDでメソッドIDを取得
Call<Type>Methodでメソッドを呼び出すCallStatic<Type>Methodでメソッドを呼び出す
<Type>にはメソッドの返り値の型と対応するInt,Short,Byteなどが入る.
流れが掴めたところでサンプルを示す.まずはネイティブコードから呼び出されるメソッドを保持するクラス.
ここにはスタティックメソッドとインスタンスメソッド,そしていろんなアクセス修飾子を混ぜてみた.次にこのクラスのメソッドをネイティブコードを介して呼び出すクラス.
そしてネイティブメソッド.まずヘッダ.
そして本体.
以下実行結果.
publicVoidMethod()
pkgPrivateIntMethod()
return 1
protectedCharMethod(hoge)
return h
privateDoubleMethod(1.0)
return 1.0
フィールドの場合と同様,privateなメソッドを呼び出したりもできる.
サンプルのネイティブコードからわかるように,インスタンスメソッドの場合は,
jmethodID mid = (*env)->GetMethodID(env, clazz, "publicVoidMethod", "()V");
(*env)->CallVoidMethod(env, methods, mid, NULL);
としてメソッドIDを取得したりそのメソッドを呼び出したりした.また,スタティックメソッドの場合は,
jmethodID mid = (*env)->GetStaticMethodID(env, clazz, "pkgPrivateStaticIntMethod", "()I");
(*env)->CallStaticIntMethod(env, clazz, mid, NULL);
としてメソッドIDを取得したりそのメソッドを呼び出したりした.GetMethodIDやCall<Type>Method系の関数名には,フィールドの取得や設定と同様の特徴がある.つまり,インスタンスメソッドの場合は関数名にStaticがつかなくて,スタティックメソッドの場合では関数名にStaticがつく.
サンプルにおいてメソッドIDを取得する部分には
jmethodID mid = (*env)->GetMethodID(env, clazz, "protectedCharMethod", "(Ljava/lang/String;)C");
などがある.なんかかなりウザイ雰囲気である.まず,第一第二引数は例によってJNIEnvとjclassである.そして第三引数はメソッド名である.そして第四引数がメソッドのシグネチャである.前の項でも書いたが,ネイティブコードでのシグネチャはJavaでいうシグネチャとは異なる.ネイティブコードでのシグネチャは
(引数の型の並び)返り値の型
で表す.すなわちメソッドの名前はシグネチャに含まれない.シグネチャは前の項で示したシグネチャ一覧を使用すると解読できる.
すでにネイティブに書かれているシグネチャを解読できたとしても,何もないところからそれを書くのは憂鬱である.引数の数が増えたり配列が絡んだりするとホントやってられない.しかも一番問題なのはコンパイラチェックが入らないことである(これはJNIのいろんなところで問題なのだが...).そんな問題に対処すべく,javapなるコマンドがある.上のサンプルもjavapのお世話になった.
$ javap -s -private Methods
Compiled from Methods.java
public class Methods extends java.lang.Object {
    public Methods();
        /*   ()V   */
    public void publicVoidMethod();
        /*   ()V   */
    static int pkgPrivateStaticIntMethod();
        /*   ()I   */
    protected char protectedCharMethod(java.lang.String);
        /*   (Ljava/lang/String;)C   */
    private static double privateStaticDoubleMethod(float);
        /*   (F)D   */
}
メソッドの宣言の次の行のコメント内がそのメソッドのシグネチャである.シグネチャの取得に必要なjavapのいくつかのオプションを以下に示す.
-s
ネイティブコードにコピペできる形式のシグネチャを出力する.
-public
publicなクラスとメンバを表示.
-protected
publicかprotectedなクラスとメンバを表示.
-package
publicかprotectedかパッケージプライベートなクラスとメンバを表示.
-private
すべてのクラスとメンバを表示.
matsu(C)
Since 2002
Mail to matsu