您的位置:首页 > 编程语言 > C语言/C++

JNI(1)之java调用c++

2013-05-11 15:31 381 查看
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;)
b4f0
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  JNI