欢迎访问 生活随笔!

凯发k8官方网

当前位置: 凯发k8官方网 > 编程资源 > 编程问答 >内容正文

编程问答

jni中参数的传递与操作 -凯发k8官方网

发布时间:2025/1/21 编程问答 18 豆豆
凯发k8官方网 收集整理的这篇文章主要介绍了 jni中参数的传递与操作 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

jni中c 和java的参数传递

如何使用jni的一些基本方法和过程在网上多如牛毛,如果你对jni不甚了解,不知道jni是做什么的,如何建立一个基本的jni程序,或许可以参考下面下面这些文章:
利用vc 6.0实现jni的最简单的例子
jni入门教程之helloworld篇
sun jni tutorial

这些资料的例子中,大多数只是输入一些简单的参数,获取没有参数。而在实际的使用过程中,往往需要对参数进行处理转换。才可以被c/c 程序识别。比如我们在c 中有一个结构(struct)diskinfo ,需要传递一个类似于diskinfo *pdiskinfo的参数,类似于在c 这样参数如何传递到java中呢?下面我们就来讨论c 到java中方法的一些常见参数的转换:

定义native java类:

如果你习惯了使用jni,你就不会觉得它难了。既然本地方法是由其他语言实现的,它们在java中没有函数体。但是,所有本地代码必须用本地关键词声明,成为java类的成员。假设我们在c 中有这么一个结构,它用来描述硬盘信息:

//硬盘信息
struct{
char name[256];
int serial;
}
diskinfo;

那么我们需要在java中定义一个类来与之匹配,声明可以写成这样:

class diskinfo {
//名字
public string name;

//序列号
publicint serial;
}

在这个类中,申明一些native的本地方法,来测试方法参数的传递,分别定义了一些函数,用来传递结构或者结构数组,具体定义如下面代码:

/****************** 定义本地方法 ********************/
//输入常用的数值类型(boolean,byte,char,short,int,float,double)
public native void displayparms(string showtext, int i, boolean bl);

//调用一个静态方法
public native int add(int a, int b);

//输入一个数组
public native void setarray(boolean[] bllist);

//返回一个字符串数组
public native string[] getstringarray();

//返回一个结构
public native diskinfo getstruct();

//返回一个结构数组
public native diskinfo[] getstructarray();

编译生成c/c 头文件

定义好了java类之后,接下来就要写本地代码。本地方法符号提供一个满足约定的头文件,使用java工具javah可以很容易地创建它而不用手动去创建。你对java的class文件使用javah命令,就会为你生成一个对应的c/c 头文件。
1、在控制台下进入工作路径,本工程路径为:e:\work\java\workspace\javajni。
2、运行javah 命令:javah -classpath e:\work\java\workspace\javajni com.sundy.jnidemo changemethodfromjni
本文生成的c/c 头文件名为: com_sundy_jnidemo_changemethodfromjni.h

在c/c 中实现本地方法

生成c/c 头文件之后,你就需要写头文件对应的本地方法。注意:所有的本地方法的第一个参数都是指向jnienv结构的。这个结构是用来调用jni函数的。第二个参数jclass的意义,要看方法是不是静态的(static)或者实例(instance)的。前者,jclass代表一个类对象的引用,而后者是被调用的方法所属对象的引用。


返回值和参数类型根据等价约定映射到本地c/c 类型,如表jni类型映射所示。有些类型,在本地代码中可直接使用,而其他类型只有通过jni调用操作。

表a

java类型本地类型描述
booleanjbooleanc/c 8位整型
bytejbytec/c 带符号的8位整型
charjcharc/c 无符号的16位整型
shortjshortc/c 带符号的16位整型
intjintc/c 带符号的32位整型
longjlongc/c 带符号的64位整型e
floatjfloatc/c 32位浮点型
doublejdoublec/c 64位浮点型
objectjobject任何java对象,或者没有对应java类型的对象
classjclassclass对象
stringjstring字符串对象
object[]jobjectarray任何对象的数组
boolean[]jbooleanarray布尔型数组
byte[]jbytearray比特型数组
char[]jchararray字符型数组
short[]jshortarray短整型数组
int[]jintarray整型数组
long[]jlongarray长整型数组
float[]jfloatarray浮点型数组
double[]jdoublearray双浮点型数组

※     jni类型映射

使用数组:

jni通过jnienv提供的操作java数组的功能。它提供了两个函数:一个是操作java的简单型数组的,另一个是操作对象类型数组的。

因为速度的原因,简单类型的数组作为指向本地类型的指针暴露给本地代码。因此,它们能作为常规的数组存取。这个指针是指向实际的java数组或者java数组的拷贝的指针。另外,数组的布置保证匹配本地类型。

为了存取java简单类型的数组,你就要要使用getxxxarrayelements函数(见b),xxx代表了数组的类型。这个函数把java数组看成参数,返回一个指向对应的本地类型的数组的指针。

表b

函数java数组类型本地类型
getbooleanarrayelementsjbooleanarrayjboolean
getbytearrayelementsjbytearrayjbyte
getchararrayelementsjchararrayjchar
getshortarrayelementsjshortarrayjshort
getintarrayelementsjintarrayjint
getlongarrayelementsjlongarrayjlong
getfloatarrayelementsjfloatarrayjfloat
getdoublearrayelementsjdoublearrayjdouble

jni数组存取函数

当你对数组的存取完成后,要确保调用相应的releasexxxarrayelements函数,参数是对应java数组和getxxxarrayelements返回的指针。如果必要的话,这个释放函数会复制你做的任何变化(这样它们就反射到java数组),然后释放所有相关的资源。

为了使用java对象的数组,你必须使用getobjectarrayelement函数和setobjectarrayelement函数,分别去get,set数组的元素。getarraylength函数会返回数组的长度。

使用对象

jni提供的另外一个功能是在本地代码中使用java对象。通过使用合适的jni函数,你可以创建java对象,get、set 静态(static)和实例(instance)的域,调用静态(static)和实例(instance)函数。jni通过id识别域和方法,一个域或方法的id是任何处理域和方法的函数的必须参数。

表c列出了用以得到静态(static)和实例(instance)的域与方法的jni函数。每个函数接受(作为参数)域或方法的类,它们的名称,符号和它们对应返回的jfieldid或jmethodid。

表c

函数描述
getfieldid得到一个实例的域的id
getstaticfieldid得到一个静态的域的id
getmethodid得到一个实例的方法的id
getstaticmethodid得到一个静态方法的id

※域和方法的函数

如果你有了一个类的实例,它就可以通过方法getobjectclass得到,或者如果你没有这个类的实例,可以通过findclass得到。符号是从域的类型或者方法的参数,返回值得到字符串,如d所示。

表d

java 类型符号
booleanz
byteb
charc
shorts
inti
longl
floatf
doubled
voidv
objects对象lfully-qualified-class-name;l类名
arrays数组[array-type [数组类型
methods方法(argument-types)return-type(参数类型)返回类型

※确定域和方法的符号


下面我们来看看,如果通过使用数组和对象,从c 中的获取到java中的diskinfo 类对象,并返回一个diskinfo数组:
//返回一个结构数组,返回一个硬盘信息的结构数组
jniexport jobjectarray jnicall java_com_sundy_jnidemo_changemethodfromjni_getstructarray
(jnienv
*env, jobject _obj)
{
//申明一个object数组
   jobjectarray args =0;

//数组大小
   jsize        len =5;

//获取object所属类,一般为ava/lang/object就可以了
   jclass objclass = (env)->findclass("java/lang/object");

//新建object数组
   args = (env)->newobjectarray(len, objclass, 0);

/* 下面为获取到java中对应的实例类中的变量*/

//获取java中的实例类
   jclass objectclass = (env)->findclass("com/sundy/jnidemo/diskinfo");

//获取类中每一个变量的定义
//名字
   jfieldid str = (env)->getfieldid(objectclass,"name","ljava/lang/string;");
//序列号
   jfieldid ival = (env)->getfieldid(objectclass,"serial","i");

//给每一个实例的变量付值,并且将实例作为一个object,添加到objcet数组中
for(int  i=0; i < len; i )
{
//给每一个实例的变量付值
       jstring jstr = windowstojstring(env,"我的磁盘名字是 d:");
//(env)->setobjectfield(_obj,str,(env)->newstringutf("my name is d:"));
       (env)->setobjectfield(_obj,str,jstr);
       (env)
->setshortfield(_obj,ival,10);

//添加到objcet数组中
       (env)->setobjectarrayelement(args, i, _obj);
   }

//返回object数组
return args;

}


全部的c/c 方法实现代码如下:
/*
*
* 一缕阳光(sundy)凯发k8官方网的版权所有,保留所有权利。
*/
/**
*
*  todo jni 中一个从java到c/c 参数传递测试类
*
*  @author 刘正伟(sundy)
*  @see
http://www.cnweblog.com/sundy
*  @see mailto:sundy26@126.com
*  @version 1.0
*  @since 2005-4-30
*
*  修改记录:
*  
*  日期              修改人                 描述
*  ----------------------------------------------------------------------------------------------
*
*
*
*/
// jnimanage.cpp : 定义 dll 应用程序的入口点。
//
package com.sundy.jnidemo;
#include
"stdafx.h"

#include
<stdio.h>
#include
<math.h>
#include
"jni.h"
#include
"jni_md.h"

#include
"./head/base.h"
#include
"head/wmi.h"
#include
"head/com_sundy_jnidemo_changemethodfromjni.h"//通过javah –jni javactransfer 生成
#include <stdio.h>
#include
"stdlib.h"
#include
"string.h"

#pragma comment (lib,
"baseinfo.lib")
#pragma comment (lib,
"jvm.lib")
//硬盘信息
struct{
char name[256];
int serial;
}
diskinfo;
/*bool apientry dllmain( handle hmodule,
                      dword  ul_reason_for_call,
                      lpvoid lpreserved
                    )
{
   lptstr  strname = new char[256] ;
   (*gethostname)(strname);
   printf("%s\n",strname);
   delete [] strname;

   return true;
}
*/
//将jstring类型转换成windows类型
char* jstringtowindows( jnienv *env, jstring jstr );
//将windows类型转换成jstring类型
jstring windowstojstring( jnienv* env, char* str );

//主函数
bool winapi dllmain(handle hhandle, dword dwreason, lpvoid lpreserved)
{
return true;
}

//输入常用的数值类型 boolean,byte,char,short,int,float,double
jniexport void jnicall java_com_sundy_jnidemo_changemethodfromjni_displayparms
(jnienv
*env, jobject obj, jstring s, jint i, jboolean b)
{
constchar* szstr = (env)->getstringutfchars(s, 0 );
   printf(
"string = [%s]\n", szstr );
   printf(
"int = %d\n", i );
   printf(
"boolean = %s\n", (b==jni_true ?"true" : "false") );
   (env)
->releasestringutfchars(s, szstr );
}


//调用一个静态方法,只有一个简单类型输出
jniexport jint jnicall java_com_sundy_jnidemo_changemethodfromjni_add
(jnienv
*env, jobject, jint a, jint b)
{
int rtn = (int)(a b);
return (jint)rtn;
}


////输入一个数组,这里输入的是一个boolean类型的数组
jniexport void jnicall java_com_sundy_jnidemo_changemethodfromjni_setarray
(jnienv
*env, jobject, jbooleanarray ba)
{
   jboolean
* pba = (env)->getbooleanarrayelements(ba, 0 );
   jsize len
= (env)->getarraylength(ba);
int i=0;
// change even array elements
for( i=0; i < len; i =2 )
{
       pba[i]
= jni_false;
       printf(
"boolean = %s\n", (pba[i]==jni_true ?"true" : "false") );
   }

   (env)
->releasebooleanarrayelements(ba, pba, 0 );
}


////返回一个字符串数组
jniexport jobjectarray jnicall java_com_sundy_jnidemo_changemethodfromjni_getstringarray
(jnienv
*env, jobject)
{
   jstring      str;
   jobjectarray args
=0;
   jsize        len
=5;
char*        sa[] ={ "hello,", "world!", "jni", "is", "fun" };
int          i=0;
   args
= (env)->newobjectarray(len,(env)->findclass("java/lang/string"),0);
for( i=0; i < len; i )
{
       str
= (env)->newstringutf(sa[i] );
       (env)
->setobjectarrayelement(args, i, str);
   }

return args;
}


//返回一个结构,这里返回一个硬盘信息的简单结构类型
jniexport jobject jnicall java_com_sundy_jnidemo_changemethodfromjni_getstruct
(jnienv
*env, jobject obj)
{
/* 下面为获取到java中对应的实例类中的变量*/

//获取java中的实例类
   jclass objectclass = (env)->findclass("com/sundy/jnidemo/diskinfo");

//获取类中每一个变量的定义
//名字
   jfieldid str = (env)->getfieldid(objectclass,"name","ljava/lang/string;");
//序列号
   jfieldid ival = (env)->getfieldid(objectclass,"serial","i");


//给每一个实例的变量付值
   (env)->setobjectfield(obj,str,(env)->newstringutf("my name is d:"));
   (env)
->setshortfield(obj,ival,10);

return obj;
}


//返回一个结构数组,返回一个硬盘信息的结构数组
jniexport jobjectarray jnicall java_com_sundy_jnidemo_changemethodfromjni_getstructarray
(jnienv
*env, jobject _obj)
{
//申明一个object数组
   jobjectarray args =0;

//数组大小
   jsize        len =5;

//获取object所属类,一般为ava/lang/object就可以了
   jclass objclass = (env)->findclass("java/lang/object");

//新建object数组
   args = (env)->newobjectarray(len, objclass, 0);

/* 下面为获取到java中对应的实例类中的变量*/

//获取java中的实例类
   jclass objectclass = (env)->findclass("com/sundy/jnidemo/diskinfo");

//获取类中每一个变量的定义
//名字
   jfieldid str = (env)->getfieldid(objectclass,"name","ljava/lang/string;");
//序列号
   jfieldid ival = (env)->getfieldid(objectclass,"serial","i");

//给每一个实例的变量付值,并且将实例作为一个object,添加到objcet数组中
for(int  i=0; i < len; i )
{
//给每一个实例的变量付值
       jstring jstr = windowstojstring(env,"我的磁盘名字是 d:");
//(env)->setobjectfield(_obj,str,(env)->newstringutf("my name is d:"));
       (env)->setobjectfield(_obj,str,jstr);
       (env)
->setshortfield(_obj,ival,10);

//添加到objcet数组中
       (env)->setobjectarrayelement(args, i, _obj);
   }

//返回object数组
return args;

}


//将jstring类型转换成windows类型
char* jstringtowindows( jnienv  *env, jstring jstr )
{
int length = (env)->getstringlength(jstr );
const jchar* jcstr = (env)->getstringchars(jstr, 0 );
char* rtn = (char*)malloc( length*21 );
int size =0;
   size
= widechartomultibyte( cp_acp, 0, (lpcwstr)jcstr, length, rtn,(length*21), null, null );
if( size <=0 )
return null;
   (env)
->releasestringchars(jstr, jcstr );
   rtn[size]
=0;
return rtn;
}

//将windows类型转换成jstring类型
jstring windowstojstring( jnienv* env, char* str )
{
   jstring rtn
=0;
int slen = strlen(str);
   unsigned
short* buffer =0;
if( slen ==0 )
       rtn
= (env)->newstringutf(str );
else
{
int length = multibytetowidechar( cp_acp, 0, (lpcstr)str, slen, null, 0 );
       buffer
= (unsigned short*)malloc( length*21 );
if( multibytetowidechar( cp_acp, 0, (lpcstr)str, slen, (lpwstr)buffer, length ) >0 )
           rtn
= (env)->newstring(  (jchar*)buffer, length );
   }

if( buffer )
       free( buffer );
return rtn;
}


java 测试native代码
这没有什么多说的,看代码吧
//主测试程序
publicstaticvoid main(string[] args) {
       changemethodfromjni changejni
=new changemethodfromjni();

//输入常用的数值类型(string int boolean)
       system.out
               .println(
"------------------输入常用的数值类型(string int boolean)-----------");
       changejni.displayparms(
"hello world!", 100, true);

//调用一个静态方法
       system.out.println("------------------调用一个静态方法-----------");
int ret = changejni.add(12, 20);
       system.
out.println("the result is: " string.valueof(ret));

//输入一个数组
       system.out.println("------------------输入一个数组-----------");
       boolean[] bllist
=new boolean[] { true, false, true };
       changejni.setarray(bllist);

//返回一个字符串数组
       system.out.println("------------------返回一个字符串数组-----------");
       string[] strlist
= changejni.getstringarray();
for (int i =0; i < strlist.length; i) {
           system.
out.print(strlist[i]);
       }

       system.
out.println();

       system.
out.println("------------------返回一个结构-----------");

//返回一个结构
       diskinfo disk = changejni.getstruct();
       system.
out.println("name:" disk.name);
       system.
out.println("serial:" disk.serial);

//返回一个结构数组

       system.
out.println("------------------返回一个结构数组 -----------");
       diskinfo[] disklist
= changejni.getstructarray();
for (int i =0; i < disklist.length; i) {
           system.
out.println("name:" disklist[i].name);
           system.
out.println("serial:" disklist[i].serial);
       }


   }


转载于:https://blog.51cto.com/laokaddk/1343401

与50位技术专家面对面20年技术见证,附赠技术全景图

总结

以上是凯发k8官方网为你收集整理的jni中参数的传递与操作的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得凯发k8官方网网站内容还不错,欢迎将凯发k8官方网推荐给好友。

  • 上一篇:
  • 下一篇:
网站地图