AndroidJNI 通过C++调用JAVA

1. JNIEnv对象    对于本地函数   JNIEXPORT void JNICALL Java_video1_TestNative_sayHello(JNIEnv * env, jobject obj)   {        cout   }           JNIEnv类型代表Java环境。通过这个JNIEnv*指针,就可以对Java端的代码进行操作。如,创建Java类得对象,调用J

大家好,又见面了,我是全栈君。

1. JNIEnv对象 

 

  对于本地函数
   JNIEXPORT void JNICALL Java_video1_TestNative_sayHello(JNIEnv * env, jobject obj)
   {  
      cout<<“Hello Native Test !”<<endl;  
   }  
   
      JNIEnv类型代表Java环境。通过这个JNIEnv*指针,就可以对Java端的代码进行操作。如,创建Java类得对象,调用Java对象的方法,获取Java对象的属性等。
     JNIEnv的指针会被JNI传送到本地方法的实现函数中来对Java端的代码进行操作

 

     
     JNIEnv类中的函数:
     
NewObject/NewString/New<TYPE>Array  :new新对象
    
 Get/Set<TYPE>Field:获取属性
    
 Get/SetStatic<TYPE>Field :获取静态属性
     
Call<TYPE>Method/CallStatic<TYPE>Method:调用方法
     
2. Java数据类型与C/C++数据类型的对应关系

 

可以参考 
jni.h
 文件:http://home.pacifier.com/~mmead/jni/cs510ajp/jni.h
 
复制代码

Java类型      别名             C++本地类型          字节(bit)  


boolean      jboolean            unsigned 
char      
8
, unsigned  


byte
         jbyte               signed 
char       
8  


char
         jchar               unsigned 
short     
16
, unsigned  


short
        jshort              
short               
16  


int
          jint                
long               
32  


long
         jlong               __int64         
64  


float
        jfloat              
float
           3
2  


double
       jdouble             
double              
64  


void         
void
                                   n/a   

复制代码

Object        _jobject            *jobject    

 

 
3. 获取jclass

 

    为了能够在C/C++使用Java类,jni.h头文件中专门定义了jclass类型来表示Java中的Class类
    jclass的取得:
    JNIEnv类中有如下几个简单的函数可以取得jclass
    jclass FindClass(const char* clsName)  根据类名来查找一个类,完整类名。
    jclass GetObjectClass(jobject obj)   根据一个对象,获取该对象的类
    jclass GetSuperClass(jclass obj)     获取一个类的父类
    
    FindClass 会在classpath系统环境变量下寻找类,需要传入完整的类名,注意包与包之间是用”/”而不是”.”来分割
如:jclass cls_string= env->FindClass(“java/lang/String”);
 
获取jclass又什么用,比如你要调用类的静态方法,静态属性就需要通过这个方法来获取一个类。

 

 
4. 本地代码访问Java类中的属性与方法 

 

 
有了类和对象之后,如何才能访问java中的对象的属性和方法呢,这就需要用到以下这些方法了。
 JNI在jni.h头文件中定义了jfieldID,jmethodID类表示Java端的属性和方法
如何获取属性: 在访问或设置Java属性的时候,首先就要现在本地代码中取得代表Java属性的jfieldID,然后才能在本地代码中进行Java属性操作。
如何调用java的方法:调用Java端的方法时,需要取得代表方法的jmethodID才能进行Java方法调用
 
JNIEnv获取相应的fieldID和jmethodID的方法:
    GetFieldID/GetMethodID
    GetStaticFieldID/GetStaticMethodID
    GetMethodID也可以取得构造函数的jmethodID。创建Java对象时调用指定的构造函数。
    如:env->GetMethodID(data_Clazz,”method_name”,”()V”)
    (*jniEnv)->GetMethodID(jniEnv, Clazz,”<init>”, “()V”); 
    这个比较特殊,这个是默认构造函数的方法,一般用这个来初始化对象,但是再实际过程中,为了快速生成一个实例,一般通过工厂方法类创建jobject
    
    jni.h 对GetMethodID的定义:
    jmethodID (JNICALL *GetMethodID)
      (JNIEnv *env, jclass clazz, const char *name, const char *sig);
      
    这就引入了一个新的问题,什么是sig,我们后面再说,举个例子说明
    前提说明: JAVA类 
TestProvider 
,该类有2个方法分别为
String getTime( )
 , 
void saysayHello( String str)
    
jclass TestProvider;

jobject mTestProvider;

jmethodID getTime;

jmethodID sayHello;
 
C 中映射类
   
TestProvider = (*jniEnv)->FindClass(jniEnv,

com/duicky/TestProvider
);

C中新建对象    

      
//
默认构造函数,不传参数

       jmethodID construction_id = (*jniEnv)->GetMethodID(jniEnv, TestProvider,

<init>


()V
);

       
//
通过NewObject来创建对象

       jobject mTestProvider = (*jniEnv)->NewObject(jniEnv, TestProvider,construction_id);
C 中映射方法 
       静态:

getTime = (*jniEnv)->GetStaticMethodID(jniEnv, TestProvider, 

getTime
,

()Ljava/lang/String;
);

       非静态:

sayHello = (*jniEnv)->GetMethodID(jniEnv, TestProvider, 

sayHello
,

(Ljava/lang/String;)V
);
C 中调用 Java的 方法
       静态:

(*jniEnv)->CallStaticObjectMethod(jniEnv, TestProvider, getTime);

       非静态:

(*jniEnv)->CallVoidMethod(jniEnv, mTestProvider, sayHello,jstrMSG);
 
注意 
Get
XXX
MethodID  和 
Call
XXX
Method 。
第一个XXX 表示的是映射方法的类型,如: 静态 跟非静态
第二个 XXX 表示 调用方法的返回值 ,如:Void,Object,等等。(调用静态方法的时候Call后面要加Static)
    
  5. sign签名
    对于 jmethodID GetMethodID(jclass clazz, const char *name, const char *sign)
    
clazz代表该属性所在的类,name表示方法名称,sign是签名
    那什么是签名,签名是对函数参数和返回值的描述,对同一个函数,在java中允许重载,这个时候就需要这个sign来进行区分了。
    以下是java类型签名的描述
    
用来表示要取得的属性/方法的类型  

 

复制代码
类型           相应的签名  


boolean        Z  


byte
           B  


char
           C  


short
          S  


int
            I  


long
           J  


float
          F  


double
         D  


void
           V  


object
         L用/分隔包的完整类名:   Ljava/lang/String; 


Array          [签名          [I      [Ljava/lang/Object;  


Method         (参数1类型签名 参数2类型签名···)返回值类型签名  
复制代码

 
特别注意:Object后面一定有分号(;)结束的,多个对象参数中间也用分号(;)来分隔

 

 
例子:
方法
签名
void
 f1()                         ()V


int
 f2(
int

long
)                 (IJ)I


boolean f3(
int
[])                 ([I)B


double
 f4(String, 
int
)            (Ljava/lang/String;I)D


void
 f5(
int
, String [], 
char
)    (I[Ljava/lang/String;C)V
 
 

 图解签名:

AndroidJNI 通过C++调用JAVA 

 

 
使用javap命令来产生签名
    
 javap -s -p [full class Name]
     -s 表示输出签名信息
     -p 同-private,输出包括private访问权限的成员信息
   
 例子:
复制代码
 C:\E\java\workspaces\myeclipseblue\JNITest\bin>javap -s –
private video1.TestNative  

Compiled 
from 

TestNative.java
  


public 
class video1.TestNative extends java.lang.Object{  


public java.lang.String name;  

  Signature: Ljava/lang/String;  


public video1.TestNative();  

  Signature: ()V  


public 
int signTest(
int, java.util.Date, 
int[]);  

  Signature: (ILjava/util/Date;[I)I  


public native 
void sayHello();  

  Signature: ()V  


public 
static 
void main(java.lang.String[]);  

  Signature: ([Ljava/lang/String;)V  

}   
复制代码

 
 

TestNative完整代码:

 
复制代码
package video1;  


import java.util.Date;  


public 
class TestNative {  

    
public String name=”Test”;  

    
public 
int number =100;  

    
public 
int signTest(
int i,Date date,
int[] arr){  

        System.out.println(“Sign Test”);  

        
return 0;  

    }  

    
//
native关键字修饰的方法,其内容是C/C++编写的,java中不必为它编写具体的实现  

    
public 
native 
void sayHello();  

    
public 
static 
void main(String[] args) {  

        System.loadLibrary(“NativeCode”);  

        TestNative tn = 
new TestNative();  

        tn.sayHello();  

    }  

}
复制代码

 
 

C/C++代码

 

 
复制代码
#include 

video1_TestNative.h
  

#include <iostream>  


using 
namespace std;  

JNIEXPORT 
void JNICALL Java_video1_TestNative_sayHello(JNIEnv * env, jobject obj){  

    cout<<

Hello Native Test !
<<endl;  

    
//
因为test不是静态函数,所以传进来的就是调用这个函数的对象  
    

//
否则就传入一个jclass对象表示native()方法所在的类  

    jclass native_clazz = env->GetObjectClass(obj);  

  

    
//
得到jfieldID  

    jfieldID fieldID_prop = env->GetFieldID(native_clazz,

name
,

Ljava/lang/String;
);  

    jfieldID fieldID_num = env->GetFieldID(native_clazz,

number
,

I
);  

  

    
//
得到jmethodID  

    jmethodID methodID_func=env->GetMethodID(native_clazz,

signTest
,

(ILjava/util/Date;[I)I
);  

    
//
调用signTest方法  

    env->CallIntMethod(obj,methodID_func,
1L,NULL,NULL);  

  

    
//
得到name属性  

    jobject name = env->GetObjectField(obj,fieldID_name);  

    
//
得到number属性  

    jint number= env->GetIntField(obj,fieldID_num);   

  

    cout<<number<<endl;
//
100  
    

//
修改number属性的值  

    env->SetIntField(obj,fieldID_num,
18880L);    

    number= env->GetIntField(obj,fieldID_num);    

    cout<<number<<endl;
//
18880  

 }  
复制代码

 

本文地址,转载请注明出处:

http://www.cnblogs.com/likwo/archive/2012/05/21/2512400.html 

 

参考资料:

 

 
jni.h 头文件:

 

相关例子:

 

Programmming in C/C++ with the Java Native Interface (3 个练习)

 

 
JNI 文档:

 

 
基于 Android NDK 的学习之旅—– C调用Java

 

 
Linux下JNI的使用:比较基础

 

 
如何在Android下使用JNI:讲解比较详细,但是代码里有些错误,空格没处理好
这篇文章有些地方不清楚的参考下这篇文章
 
Android Jni代码示例讲解

 

JNI callMethod参考文档

 

其他推荐学习网站

 

JNI的提高,Java类型和C(C++)类型转换源代码

http://blog.csdn.net/ostrichmyself/article/details/4557851 

 

JNI 的多线程

 http://blog.csdn.net/popop123/article/details/1511180 

 

Android NDK 开发 

 

 

使用 Java Native Interface 的最佳实践:描述了JNI性能和缓存的一些东西

 

 https://www.ibm.com/developerworks/cn/java/j-jni/

 

JNI 攻略系列

JNI全攻略之一--建立一个简单的JNI程序 

http://blog.csdn.net/yjkwf/article/details/7006260 

JNI全攻略之二――JNI基础 

http://blog.csdn.net/yjkwf/article/details/7006261 

 JNI全攻略之三--JNI头文件分析

 http://blog.csdn.net/yjkwf/article/details/7006264

 JNI攻略之四――JNI操作数组

http://blog.csdn.net/yjkwf/article/details/7006266 

 

http://disanji.net/2011/01/26/android-jni-programming-2/ 

 

 JNI Examples for Android

http://android.wooyd.org/JNIExample/files/JNIExample.pdf 

 

JNI pthread 多线程使用

http://www.cnblogs.com/lknlfy/archive/2012/03/16/2400786.html 

本文转自http://www.cnblogs.com/likwo/archive/2012/05/21/2512400.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/121338.html原文链接:https://javaforall.net

(0)
上一篇 2022年3月11日 下午12:00
下一篇 2022年3月11日 下午12:00


相关推荐

  • java 启动连接hsql

    java 启动连接hsqljava启动连接HSQL转载自: http://ehilcoder.iteye.com/blog/17228051.关于HSQLAHyperSQLDatabaseEachHyperSQLdatabaseiscalledacatalog.Therearethreetypesofcatalogdependingonhowthedataisstored.Typ

    2025年12月10日
    4
  • JVM-内存结构「建议收藏」

    JVM-内存结构「建议收藏」分享一个大牛的人工智能教程。零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来!请点击http://www.captainbed.netJVM在执行程序的过程中会将内存划分为不同的数据区域,请看下图。如果理解了上图,JVM的内存结构基本上掌握了一半。从图中可以得到如下信息。第一,JVM分为五个区域:虚拟机栈、本地方法栈、方法区、堆、程序计数器。第二,JVM五个区中虚拟机栈、本地方法栈、程序计数器为线程私有,方法区和堆为线程共享区。图中已经用颜色区分。第三,JVM不同区域占用的内

    2022年6月4日
    34
  • matlab画时域和频谱图_信号的频域分析及matlab实现

    matlab画时域和频谱图_信号的频域分析及matlab实现随机振动信号分析方法总结信号处理(信号滤波、时频域分析、神经网络、寿命预测)一、时域分析时域分析特征包括均值、方差、峭度、峰峰值等;振动信号降噪结果分析:对于去噪效果好坏的评价,常用信号的信噪比(SNR)、估计信号同原信号的均方根误差(RMSE)来判断。SNR越高则说明混在信号里的噪声越小,否则相反。RMSE的计算值越小则表示去噪效果越好。信噪比定义:均方根误差定义:二、频域分析三、时频联合域分析(JointTime-FrequencyAnalysis,JTFA)即时频分析,

    2022年10月15日
    3
  • 图像形态学操作—腐蚀扩展深度

    图像形态学操作—腐蚀扩展深度

    2022年1月14日
    50
  • leanback android,Android TV Leanback (五)(使用leanback创建UI)

    leanback android,Android TV Leanback (五)(使用leanback创建UI)创建浏览布局 leanback 库的 BrowseFragme 允许您创建一个主要布局 以最少的代码浏览媒体项的类别和行 代码示例如下 android id id main frame android layout width match parent android layout height match parent gt android name com example andro

    2026年3月19日
    2
  • OpenClaw(Clawdbot)+Skills集成小白教程:2026年京东云一键部署基础教学

    OpenClaw(Clawdbot)+Skills集成小白教程:2026年京东云一键部署基础教学

    2026年3月13日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号