Java 側のメソッドを C 側から呼んでみた。手順を踏まないといけないところが面倒だ。
引数の渡し方とか、戻り値の受け取り方とか、クラスを使った場合など、ちょっと追加で調べてみたいかも。

ソースコード

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "jni.h"

int main(int argc, char **argv)
{
    JNIEnv         *jenv;
    JavaVM         *jvm;
    JavaVMInitArgs jvm_args;
    JavaVMOption   jvm_options[1];
    jclass         klass;
    jmethodID      mid;
    int            ret;

    jvm_options[0].optionString = "-Djava.class.path=./java";

    jvm_args.version            = JNI_VERSION_1_6;
    jvm_args.options            = jvm_options;
    jvm_args.nOptions           = 1;
    jvm_args.ignoreUnrecognized = 1;

    ret = JNI_CreateJavaVM(&jvm, (void**)&jenv, &jvm_args);
    if (ret < 0) {
        fprintf(stderr, "cannot create JVM\n");
        exit(1);
    }

    klass = (*jenv)->FindClass(jenv, "HelloWorld");
    if (klass == 0) {
        fprintf(stderr, "cannot find class\n");
        exit(1);
    }

    // public static void main (String[] args)
    mid = (*jenv)->GetStaticMethodID(jenv, klass, "main", "([Ljava/lang/String;)V");
    if (mid == 0) {
        fprintf(stderr, "cannot get method id\n");
        exit(1);
    }

    (*jenv)->CallStaticVoidMethod(jenv, klass, mid, NULL);

    (*jvm)->DestroyJavaVM(jvm);

    exit(0);
}

コンパイル

gcc -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -Wall -c sample.c
gcc -L$JAVA_HOME/jre/lib/i386/client -ljvm -o main sample.o

Java 側のソースコード

public class HelloWorld {
    public static void main (String[] args) {
        System.out.println("Hello world");
    }
}

実行

LD_LIBRARY_PATH=$JAVA_HOME/jre/lib/i386/client ./main

実行結果

Hello world