JNI(1)之java調用c++

1:vs2010創建新的動態鏈接庫 (DLL) 項目:

1.1:從“文件”菜單中,選擇“新建”,然後選擇“項目…”。

1.2:從“項目類型”窗格中選擇“Visual C++”下的“Win32”。

1.3:從“模板”窗格中,選擇“Win32 控制檯應用程序”。

1.4:爲項目起一個名稱

1.5:在“Win32 應用程序嚮導”對話框的“概述”頁中,按“下一步”

1.6:從“Win32 應用程序嚮導”中的“應用程序設置”頁中,選擇“應用程序類型”下的“DLL“

1.7:從“Win32 應用程序嚮導”的“應用程序設置”頁中,選擇“附加選項”下的“空項目”。

2:導入JNI庫,首先確定你裝好JDK

2.1:右鍵選擇你的項目-》屬性-》配置屬性-》c/c++(新建2個c++文件纔會顯示)-》常規,點擊附加包含目錄,編輯如圖:

2.1:添加2個路徑如圖:

3:開始java端程序打開eclipse:

3.1:我的代碼如下:

package com.myjava;

public class HelloWorld {
 private native String print(String str);
 private native int[] sumArray(int[] arr);
 int a=1;
 static int sa=2;
 native void seta_sa();
 //實例方法
 void callStr(String str,int a[]){
  
  System.out.println(str);
  for(int i=0;i<a.length;i++)System.out.println(a[i]);
 }
 native void nativeCallStr();
 //構造方法
 native Hi gouzaoHi();
 //修改成員數組
 String myStr[]={"dd","aaa"};
 public String[] getMyStr() {
  return myStr;
 }
 public void setMyStr(String[] myStr) {
  this.myStr =myStr;
 }
 public static void main(String[] args) {
  HelloWorld hw=new HelloWorld();
  //字符串
//    String s=hw.print("yyy");
//    System.out.println(s);
    //數組
//    int a[]={1,2,4};
//    int sum[]=hw.sumArray(a);
//    for(int i=0;i<sum.length;i++)
//    System.out.println(sum[i]);
  //成員變量
//  hw.seta_sa();
//  System.out.println("java a:"+hw.a);
//  System.out.println("java sa:"+sa);
  //成員方法
//  hw.nativeCallStr();
  //構造方法
//  Hi hi=(Hi)hw.gouzaoHi();
//  System.out.print(hi.hiStr);;
  ////修改成員數組
  hw.nativeCallStr();
  for(int i=0;i<hw.myStr.length;i++)
  System.out.println("java:修改後 "+hw.myStr[i]);
  
 }
 static {//加載dll庫
 System.loadLibrary("myJNITest");
 }
}

下面爲第2個類:

package com.myjava;

public class Hi {
 String hiStr="nihao hi";
    Hi(String str){System.out.println("class Hi str:"+str);}
}

好的開始編譯生成class文件但會報錯沒關係只要生成class文件即可

4:開始-》運行,輸入cmd打開並定位到你java項目的bin文件夾下:

4.2:輸入命令javap -s -p -classpath 包名路徑 包名.文件名:

這樣你可以看到一堆與你java文件有關的對應JNI反編譯信息

4.3:生成頭文件輸入命令javah -classpath 包名路徑 包名.文件名:

你可以在你開始定位的java文件下看到.h文件:如我的在

5:現在在VS2010建一個.h文件一個.cpp文件,上步生成的.h文件內容對應此處生成的文件(讀者若有疑惑可以看看JNI一些基礎教程):

5.1:下面我的.h文件內容:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_myjava_HelloWorld */

#ifndef _Included_com_myjava_HelloWorld
#define _Included_com_myjava_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_myjava_HelloWorld
 * Method:    print
 * Signature: ()V
 */
JNIEXPORT jstring JNICALL Java_com_myjava_HelloWorld_print
  (JNIEnv *, jobject,jstring);

JNIEXPORT jintArray JNICALL Java_com_myjava_HelloWorld_sumArray
  (JNIEnv *, jobject, jintArray);

JNIEXPORT void JNICALL Java_com_myjava_HelloWorld_seta_1sa
  (JNIEnv *, jobject);
/*
 * Class:     com_myjava_HelloWorld
 * Method:    nativeCallStr
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_myjava_HelloWorld_nativeCallStr
  (JNIEnv *, jobject);

JNIEXPORT jobject JNICALL Java_com_myjava_HelloWorld_gouzaoHi
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

5.2 .cpp文件內容:

#include <jni.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include "HelloWorld.h"
using namespace std;
JNIEXPORT jstring JNICALL Java_com_myjava_HelloWorld_print(JNIEnv *env, jobject obj,jstring prompt)
{
  char buf[128];
const char *str;
//調用GetStringUTFChars,把1個Unicode字串轉成UTF-8格式字串,第2參數爲JNI_TRUE,將返回str的一個拷貝;爲
//JNI_FALSE將直接指向str的內容,當isCopy爲JNI_FALSE設爲NULL,不關心Java VM對返回的指針是否直接指向java.lang.String的內容
str = (env)->GetStringUTFChars(prompt, NULL);
if (str == NULL) {
return NULL;
}
scanf("%127s", buf);

printf("%s", str);
//調用ReleaseStringUTFChars釋放GetStringUTFChars中分配的內存
(env)->ReleaseStringUTFChars(prompt, str);
//使用JNIEnv->NewStringUTF構造java.lang.String;如果此時沒有足夠的內存,
//NewStringUTF將拋OutOfMemoryError異常,同時返回NULL
return (env)->NewStringUTF(buf);
}
//數組
JNIEXPORT jintArray JNICALL Java_com_myjava_HelloWorld_sumArray
 (JNIEnv *env, jobject obj, jintArray arr){
  jintArray jarr;
  jint *carr;
jint i, sum = 0;
carr = env->GetIntArrayElements(arr, NULL);
if (carr == NULL) {
return 0; /* exception occurred */
}
for (i=0; i<env->GetArrayLength(arr); i++) {
sum += carr[i];
printf("%s,%d\n","c++的輸出",carr[i]);
}
//新建數組
int len=2;
int backArr[]={11,12};
jarr=env->NewIntArray(len);
env->SetIntArrayRegion(jarr,0,len,(jint*)backArr);
//釋放空間
env->ReleaseIntArrayElements(arr,carr,0);
env->ReleaseIntArrayElements(jarr,(jint*)backArr,0);
return jarr;
}
//修改成員變量
JNIEXPORT void JNICALL Java_com_myjava_HelloWorld_seta_1sa
 (JNIEnv *env, jobject obj){
  jfieldID fid;
  jint ja,jsa;
  jclass cls = env->GetObjectClass(obj);
  //通過GetFieldID得到對象成員ID,第2參數對應屬性變量a,第3參數對應屬性a的jni簽名
  fid = env->GetFieldID(cls, "a", "I");
  ja=env->GetIntField(obj,fid);
  cout<<"c++ ja:"<<ja<<endl;
  env->SetIntField(obj,fid,ja+10);
  //獲得靜態id
  fid= env->GetStaticFieldID(cls, "sa", "I");
  jsa=env->GetStaticIntField(cls,fid);
  cout<<"C++ jsa:"<<jsa<<endl;
  env->SetStaticIntField(cls,fid,jsa+10);
}
//調用成員方法
JNIEXPORT void JNICALL Java_com_myjava_HelloWorld_nativeCallStr
 (JNIEnv *env, jobject obj){
  jclass cls =env->GetObjectClass(obj);
  //第2參數方法名,第3參數Ljava/lang/String;爲string簽名,[I爲數組簽名,V爲返回類型
  jmethodID mid =env->GetMethodID(cls, "callStr", "(Ljava/lang/String;[I)V");
  if (mid == NULL) {
   return;
  }
  int len=2;
        jint backArr[]={11,12};
        jintArray jarr=env->NewIntArray(len);
  env->SetIntArrayRegion(jarr,0,2,(jint*)backArr);
  env->ReleaseIntArrayElements(jarr,backArr,0);
  //第3個參數爲傳遞的值
  env->CallVoidMethod(obj,mid,env->NewStringUTF("hello"),jarr);
  //調用成員方法修改成員字符串數組,先獲得再修改
  mid =env->GetMethodID(cls, "getMyStr", "()[Ljava/lang/String;");
  jobjectArray msg=(jobjectArray)env->CallObjectMethod(obj, mid);
  len =env->GetArrayLength(msg);
  for(int i=0;i<len;i++){
   jobject jo=env->GetObjectArrayElement(msg,i);
      cout<<"C++:字符串數組修改前:"<<(env)->GetStringUTFChars((jstring)jo, NULL)<<endl;
  }
  string sa[] = { "Hello", "world!", "JNI", "is", "fun" };
  mid =env->GetMethodID(cls, "setMyStr", "([Ljava/lang/String;)V"); 
  jobjectArray args = (env)->NewObjectArray(sa->length(),(env)->FindClass("java/lang/String"),0);
  for( int i=0; i <sa->length(); i++ ){
   (env)->SetObjectArrayElement(args, i,(env)->NewStringUTF(sa[i].c_str()));
  }
  env->CallObjectMethod(obj, mid,args);
  env->DeleteLocalRef(args);
}
//構造方法
JNIEXPORT jobject JNICALL Java_com_myjava_HelloWorld_gouzaoHi
 (JNIEnv *env, jobject obj){
  jclass hiClass;
  jmethodID cid;
  //類的路徑
  hiClass =env->FindClass("com/myjava/Hi");
  if(hiClass==NULL)return NULL;
  //第2參數,構造方法爲<init>
  cid =env->GetMethodID(hiClass, "<init>", "(Ljava/lang/String;)V");
  if(cid==NULL)return NULL;
  jobject jo=env->NewObject(hiClass,cid,env->NewStringUTF("gouzaoHi"));
  env->DeleteLocalRef(hiClass);
  return jo;
}

6:至此爲止所有準備做好,右鍵你的項目-》生成:ok你可以再你的c++項目debug文件下發現生成的.dll文件如:我的爲myJNITest.dll

 

7:拷貝他放入你的java項目如:

8:運行java文件即可(java文件有多個註釋,每個註釋對應不同的JNI調用方式讀者參考),若讀者想知道c++如何調用java可看下篇JNI(2)之c++調用java

項目地址:http://download.csdn.net/detail/qwezcl/5356079

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章