MEDIA

メディア

  1. TOP
  2. メディア
  3. プログラミング
  4. Java JNI入門|C/C++連携と実装手順を完全解説

Java JNI入門|C/C++連携と実装手順を完全解説

JNIとは?仕組みとできること

「JavaからC/C++を呼び出せるらしいけど、どうやって動いているの?」

そう疑問に思ったことはないでしょうか。

JNI(Java Native Interface)は、JavaとC/C++などのネイティブコードを接続する標準インターフェースです。

JNIでできること

  • JavaからC/C++関数を呼び出す
  • C/C++からJVMを起動する
  • Javaオブジェクトを操作する
  • 配列・文字列を受け渡す
  • 例外をネイティブ側から送出する

JNIは「Javaの外側」にある世界と接続する橋渡し役です。

通常、JavaはJVM上で完結します。しかしJNIを使うと、OS固有機能や既存のC/C++資産を活用できます。

なぜ低レベルなのか?

JNIはVM内部構造に依存しない設計です。そのため安全ですが、APIはやや複雑です。

  • 参照管理は手動
  • メモリ管理も開発者責任
  • 呼び出しコストが存在

つまり「強力だが扱いは慎重に」という技術です。

まとめ

  • JNIはJavaとネイティブの橋渡し
  • 双方向呼び出しが可能
  • 強力だが設計が重要

JNIを理解すると、Javaの限界を突破できます。

C言語についてはこちらの記事にて解説載っておりますのでご参考ください!

JNIが必要になるケースと設計判断

JNIは万能ではありません。適用判断が重要です。

主な利用ケース

① 既存C/C++資産の活用

  • 暗号処理
  • 画像処理
  • デバイスSDK
  • 高速数値計算

長年検証されたネイティブコードを活かせます。

② OS固有機能へのアクセス

Java標準APIでは触れない機能があります。

例:

  • 専用ドライバ制御
  • ネイティブSDK限定機能

③ JVM組み込み(逆方向)

既存C/C++製品にJava機能を追加するケースです。

性能目的での利用は要注意

JNI呼び出しには「境界越えコスト」があります。

Java → JNI → C/C++ → JNI → Java

小さな処理を大量に呼ぶと逆に遅くなります。

✔ 呼び出し回数を減らす

✔ まとめて処理する設計にする

これが成功の鍵です。

まとめ

  • JNIは必要な時だけ使う
  • 設計判断が最重要
  • 性能目的なら境界設計を意識

JNI開発に必要な環境と前提知識

JNIにはJava環境だけでは不十分です。

必要なもの

必要物 内容
JDK ヘッダ(jni.h)が必要
C/C++コンパイラ GCC / MSVC
ビット数一致 JVMとDLL/soを合わせる

JDKは必須

JREでは不十分です。

echo %JAVA_HOME%
echo $JAVA_HOME

設定を確認しましょう。

JDK?JRE?と思った方、改めて確認したい方などぜひこちらの記事もご参考ください!

JNIヘッダの場所

JAVA_HOME/include
JAVA_HOME/include/win32
JAVA_HOME/include/linux

ここをインクルードパスに追加します。

よくある失敗

  • 32bit/64bit不一致
  • DLLはあるが依存DLL不足
  • java.library.path未設定

環境構築で止まる人は非常に多いです。

💡 実務スキルを伸ばしたい人へ

JNIのような実践的テーマは、環境構築だけで消耗しがちです。

ZeroCodePlusなら:

  • ブラウザ上でJava実行
  • 実務想定の課題形式
  • JVM理解が深まる演習

環境に時間を奪われず、本質理解に集中できます。

Java→C/C++連携の基本手順【コード例】

① Java側

public class HelloJNI {

 static {
  System.loadLibrary("hello");
 }

 public native String sayHello(String name);

 public static void main(String[] args) {
  HelloJNI h = new HelloJNI();
  System.out.println(h.sayHello("Taro"));
 }
}

② ヘッダ生成

javac -h . HelloJNI.java

③ C側実装

#include <jni.h>
#include "HelloJNI.h"

JNIEXPORT jstring JNICALL
Java_HelloJNI_sayHello(JNIEnv *env, jobject obj, jstring name) {

 const char *str = (*env)->GetStringUTFChars(env, name, 0);

 char buffer[256];
 sprintf(buffer, "Hello %s from C!", str);

 (*env)->ReleaseStringUTFChars(env, name, str);

 return (*env)->NewStringUTF(env, buffer);
}

④ ポイント

  • GetとReleaseは必ずセット
  • JNIEnvはスレッドローカル
  • シグネチャ不一致に注意

Windows/Linuxでのビルド方法

Windows(MinGW例)

gcc -I"%JAVA_HOME%/include" ^
-I"%JAVA_HOME%/include/win32" ^
-shares -o hello.dll HelloJNI.c

Linux

gcc -fPIC -I"$JAVA_HOME/include" \
-I"$JAVA_HOME/include/linux" \
-shared -o libhello.so HelloJNI.c

実行時

Java -Djava.library.path=. HelloJNI

よくあるエラー

  • UnsatisfiedLinkError
  • 依存ライブラリ不足
  • パス設定ミス

JNIの8割は環境問題です。

JNIプログラミングの重要ポイント

1. 参照管理

ローカル参照は大量生成すると上限に達します。

必要なら:

(*env)->Deleted.ocalRef(env,obj);

2. 例外処理

jclass ex = (*env)->FindClass(env, "java/lang/RuntimeException");
(*env)->ThrowNew(env, ex, "Error occyrred");

例外後は処理を続けないこと。

3. スレッド管理

別スレッド使用時:

(*jvm)->AttachCurrentThread(1・・・)

必ずDetachする。

C/C++からJavaを起動する(Invocation API)

JVM生成

JNI_Create.JavaVM(%jvm, (void**)&env, &vm_args);

Javaメソッド呼び出し

jclass cls = (*env)->FindClass(env, "Hello");
jmethodID miid = (*env)->GetStaticMethodid(env, "main", "([Ljava/lang/String;)V");

注意点

  • クラス名はスラッシュ区切り
  • シグネチャ文字列一致必須
  • 例外確認を忘れない

JNIの注意点と実務ベストプラクティス

デメリット

移植性低下

デバッグ難易度上昇

JVMクラッシュリスク

実務で守ること

✔ 境界は小さく保つ

✔ 例外時もリソース解放

✔ IDはキャッシュする

✔ 呼び出し回数を減らす

JNIは「最小限で使う」のが鉄則です。

まとめ

JNIは強力な武器です。

  • JavaとC/C++を接続できる
  • OS固有機能を利用できる
  • 既存資産を活用できる

しかし設計を誤ると不安定になります。

まずは最小サンプルを動かしましょう。その上で徐々に拡張するのが安全です。

JNIを理解できれば、

「Javaが分かるエンジニア」から

「実行基盤まで理解するエンジニア」へ進化できます。

Join us! 未経験からエンジニアに挑戦できる環境で自分の可能性を信じてみよう 採用ページを見る→

記事監修

ドライブライン編集部

[ この記事をシェアする ]

記事一覧へ戻る