JNI学习笔记

合集下载

JNA学习笔记

JNA学习笔记

JNA学习笔记JNA是什么:JNA(Java Native Access )提供一组Java工具类用于在运行期动态访问系统本地库(native library:如Window的dll)而不需要编写任何Native/JNI代码。

开发人员只要在一个java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射。

JNA优点:JNA可以让你像调用一般java方法一样直接调用本地方法。

就和直接执行本地方法差不多,而且调用本地方法还不用额外的其他处理或者配置什么的,也不需要多余的引用或者编码,使用很方便。

JNA使用:1)POM<dependencies><dependency><groupId>net.java.dev.jna</groupId><artifactId>jna</artifactId><version>3.4.0</version></dependency></dependencies>在POM文件中加入上述dependency2)准备一个dll文件示例文件(仅核心代码):的相关使用部分。

将编译得到的dll文件(这里是”JNATestDll.dll”)放在java工程的根目录下(根据需要,可以自行调整)3)编写Java代码2.接口继承自com.sun.jna.Library。

3.接口内部需要定义一个公共静态常量(这里是instanceDll),通过它调用dll的相关函数。

3-2)带有基本变量参数的接口调用JNA提供了Java和C数据类型的映射3-3)简单指针和引用(不需要Java分配空间,非自定义结构体,不含多级指针)2. 一级指针和引用都使用ByReference作为参数3-4)简单数组(内部类型数组)3-5)自定义简单结构体调用部分2. 结构体中公共参数的顺序、类型必须一致3-6)结构体内嵌套数组(使用网上示例,不包含指针)Tips 1.结构体必须在内部进行数组定义C语言的结构体是一段连续的内存,内存的大小是编译时确定的。

java从入门到精通学习笔记-Lesson3(native方法)

java从入门到精通学习笔记-Lesson3(native方法)

native方法●Sun公司提供的JNI是Java平台的一个功能强大的接口。

这个JNI接口提供了Java与操作系统本地代码互相调用的功能。

●Native方法是用户在Java中可以使用,但不能编写的方法。

●JNI(Java Native Interface Java本地接口),它允许Java虚拟机(JVM)内部运行的Java代码能够与用其它编程语言(如C、C++、汇编语言)编写的应用程序和库进行互操作。

●JNI最大的好处是它没有对底层Java虚拟机的实现施加任何限制,因此,Java虚拟机厂商可以在不影响虚拟机其它部分的情况下添加对JNI的支持。

程序员只需编写一种版本的本地(Native)应用程序和库,就能够与所有支持JNI 的Java虚拟机协同工作。

●JNI可以理解为Java和本地应用程序之间的中介。

那么我们什么时候使用JNI呢?如果我们想要访问操作系统的特有功能,想要同特殊的硬件设备沟通,我们可以使用JNI技术,利用其它语言去实现、去调用、去访问操作系统的特有功能。

如果我们想重复使用过去编写的非java语言编写的代码,我们也可以使用JNI 技术。

如果我们想实现实时性很强的代码,可以采用其它语言去实现,如C和汇编语言,然后用JNI技术在Java中调用这种实现。

用本地方法编写一个Java程序(以HelloW orld.java为例):一、写Java代码:class HelloWorld {public native void displayHelloWorld();static {System.loadLibrary("hello");}public static void main(S tring[] args) {new HelloWorld().displayHelloWorld();}}二、编译Java代码:javac HelloWorld.java三、创建. h 的文件javah -jni HelloWorld产生的HelloWorld.h文件如下:/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class HelloWorld */#ifndef _Included_HelloWorld#define _Included_HelloWorld#ifdef __cplusplusextern "C" {#endif/** Class: HelloWorld* Method: displayHelloWorld* Signature: ()V*/JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld(JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif四、写一个本地方法的实现新建HelloWorldImp.c#include <jni.h>#include "HelloWorld.h"#include <stdio.h>JNIEXPORT void JNICALLJava_HelloWorld_displayHelloWorld(JNIEnv *env, jobject obj)//HelloWorld.h中声明的函数原型{printf("Hello world!\n");return;}第五步:创建一个共享的库cl -I C:\Java\j2sdk1.5.0\include-I C:\Java\j2sdk1.5.0\include\win32 -LD HelloWorldImp.c -Fehello.dll这里的cl是安装了Visual C++而提供的编译工具。

JAVA(J2SEJ2EE)学习笔记090911

JAVA(J2SEJ2EE)学习笔记090911

JAVA(J2SE/J2EE)JAVA(J2SE/J2EE)学习笔记学习笔记/kv2004Java Paradise 群号:81556987,欢迎传播!JA V A(J2SE)基础一、JAVA 语法基础标识符-date:0908111.什么叫标识符?就是一个名字2.在JAVA 中,遇见的标识符有类名、方法名和变量名。

3.标识符的命名规则:i.标识符有字母、数字、下划线(_)以及美元($)符号组成。

ii.标识符不能以数字开头iii.不能和JAV A 中的关键字或者保留字重名4.标识符的命名规范:i.最好不要一下划线(_)或者美元($)符号开头ii.如果有多个单词组成,那么每个字符的首字符都大写。

例如:class Student{}class HelloWorld{}iii.如果标识符是方法名或者变量名:首字母应该小写;如果有多个单词组成,那么从第二个单词开始,首字母大写。

例如:String name;//用户名int stuAge;//学生的年龄iv.标识符最好有一定的意义。

int 整数=1;v.如果是常量名,那么全部字母都大写。

final double PI=3.1415926;关键字-date:0908111.什么叫关键字?具有特殊意义的一些单词。

2.举例说出几个关键字byte short int long float double char booleanpublic private protectedvoidreturntrue falsestatic final abstractif elseswitch caseforwhiledotry catchcontinuebreak数据类型的转换-date:0908111.基本数据类型可以相互转换(除boolean)2.可以将低精度的数据类型直接赋值给高精度的数据类型int i=1;short s=1;i=s;//可以自动进行转换3.当把高精度的数据类型赋值给低精度的数据类型时,必须强制类型转换。

JAVA本地接口(JNI)编程指南和规范

JAVA本地接口(JNI)编程指南和规范
我从 Craig J.Bordelon, Michael Brundage, Mary Dageforde, Joshua Engel and Elliott Hughes 处 得到关于这本书草稿有价值的评论。
Lisa Friendly, The Java Series 的编者,有助于这本书的编写和出版。Ken Arnold, The Java Programming Language 得到作者,首先提出了 JNI 书的编写。我要感谢在整个过程中 Mike hedrikson 和 Marina Lang 给的帮助和耐心在 Addison-Wesley 出版社。Diance 监督了生产流 程从复制,编辑和最后的打印。
这章剩余的部分介绍 JNI 的背景,作用和演化。
1.1 The Java Platform and Host Environment(Java 平台和主机环境) 这本书时间用 Java 编程语言和用本地编程语言(C,C++等(etc.))来写应用程序.让我们先为这
些语言,明确正确的编程环境区域。
"Java"平台的编程环境包含"Java"虚拟机(VM)和 Java 应用程序编程的接口(Java Application Programming Interface(API))。"Java"应用程序是用"Java"编程语言编写的,被编译成一个独 立于机器(machine-independent)二进制类格式.一个类在任何 Java 虚拟机上执行实现。Java 的 API 包含预定义的类集合。Java"平台的任何实现被假设支持 Java 编程语言,虚拟机和"API"。
这本书假设你有"Java,C 和 C++"编程语言的基本知识。如果没有,你可以参考许多有用的 优秀的书本:Ken Arnold and James Gosling(Addison-Wesley,1998)写的"The Java Programming Language, Second Edittion", Brian Kere Hall,1988)写的"The C Programming Language, Second Edition"和 Bjarne Stroustrup(Addison-Wesley 1997)写的"The C++ Programming Language, Third Edition".

jni编译

jni编译

jni编译Jni编译入门教程什么是jni编译?JNI(Java Native Interface)是Java语言的一个标准编程接口,它允许Java程序调用原生(C、C++)的代码或者原生代码调用Java程序,它为Java和C/C++互操作提供了支持。

而JNI编译,则是将Java和C/C++代码进行链接的过程,它是一种将Java和C/C++代码融合的编译方法,使Java和C/C++能够相互调用。

Jni编译步骤JNI编译需要经过以下步骤:1. 编写Java代码和C/C++代码首先需要编写Java代码以及对应的C/C++代码。

Java代码必须实现native方法,以便在运行时调用C/C++代码。

2. 编写Java头文件Java头文件定义了Java代码中要调用的C/C++函数的接口,需要使用Java的javah命令自动生成。

3. 编写C/C++代码C/C++代码实现了用于处理Java传递的数据和返回值的函数。

由于不同的操作系统有不同的调用约定,因此,C/C++代码必须使用操作系统特定的调用方法,如stdcall、cdecl等。

4. 编译C/C++代码使用C/C++编译器将C/C++代码编译成共享库,不同的操作系统需要编译出不同的共享库,如Windows平台上生成的是.dll文件,Unix平台上生成的是.so文件。

5. 将共享库链接到Java虚拟机使用Java虚拟机提供的JNI接口将共享库加载到Java虚拟机中,并在Java代码中调用C/C++代码,完成Java和C/C++代码间的数据传递和交互。

Jni编译实例下面用一个简单的例子,演示一下如何进行Jni编译。

步骤一:编写Java代码和C/C++代码Java代码:```package com.example;public class JniTest {public native String hello();static {System.loadLibrary("jni_lib");}}```C/C++代码:```#include "com_example_JniTest.h"JNIEXPORT jstring JNICALL Java_com_example_JniTest_hello(JNIEnv *env, jobject obj){return env->NewStringUTF("Hello, world!");}```步骤二:编写Java头文件在终端中进入代码目录并运行以下命令,生成Java头文件。

JNI技术实践小结

JNI技术实践小结

JNI技术实践小结昨天和一部zzz一起研究解决一个java调用第三方dll的问题,从零开始学习了jni技术的应用,现在总结如下。

事情的起因是一部的一个项目需要用到一个爱国者提供的基于U盘的加密技术。

对方提供了U盘和一个dll动态链接库hiddenIO.dll。

在U盘的隐藏区域内可以储存USB-Key信息,通过这个dll里的两个方法可以使用c/c++编写程序在U盘的隐藏区域读写信息,对方提供了示例代码。

由于一部的项目是基于SWT/RCP 技术的,所以需要在java程序中调用这两个方法。

目前java与dll交互的技术主要有3种:jni,jawin和jacob。

Jni(Java Native Interface)是sun提供的java 与系统中的原生方法交互的技术(在windows\linux系统中,实现java与native method互调)。

目前只能由c/c++实现。

后两个都是sourceforge上的开源项目,同时也都是基于jni技术的windows系统上的一个应用库。

Jacob(Java-Com Bridge)提供了java程序调用microsoft的com对象中的方法的能力。

而除了com对象外,jawin(Java/Win32 integration project)还可以win32-dll动态链接库中的方法。

就功能而言:jni >> jawin>jacob,其大致的结构如下图:JNI技术体系功能结构图就易用性而言,正好相反:jacob>jawin>>jni。

Jvm封装了各种操作系统实际的差异性的同时,提供了jni技术,使得开发者可以通过java程序(代码)调用到操作系统相关的技术实现的库函数,从而与其他技术和系统交互,使用其他技术实现的系统的功能;同时其他技术和系统也可以通过jni提供的相应原生接口开调用java应用系统内部实现的功能。

在windows系统上,一般可执行的应用程序都是基于native的PE结构,windows上的jvm也是基于native 结构实现的。

JNI编程指南(详细)

JNI编程指南(详细)

序这四种情况下你会用到本书:1、在Java程序中复用以前写过的C/C++代码。

2、自己实现一个java虚拟机3、学习不同语言如何进行协作,尤其是如何实现垃圾回收和多线程。

4、把一个虚拟机实现整合到用C/C++写的程序中。

本书是写给开发者的。

JNI在1997年第一次发布,本书总结了SUN工程师和大量开发者两年来积累的经验。

本书介绍了JNI的设计思想,对这种思想的理解是使用JNI的各种特性的基础。

本书有一部分是JA VA2平台上面的JNI特征的规范说明。

JNI程序员可以把这部分用作一个手册。

JVM开发者在实现虚拟机的时候必须遵守这些规范。

JNI的部分设计思想来源于Netscape的Java Runtime Interface(JRI)。

第一章简介JNI是JA V A平台的一个重要特征,使用它我们可以重用以前用C/C++写的大量代码。

本书既是一个编程指南也是一个JNI手册。

本书共包括三部分:1、第二章通过一个简单的例子介绍了JNI。

它的对象是对JNI不熟悉的初学者。

2、3~10章对JNI的特征进行了系统的介绍。

我们会举大量的例子来说明JNI的各个特征,这些特征都是JNI中重要且常用的。

3、11~13章是关于JNI的技术规范。

可以把这两章当作一个手册。

本书尽量去满足各类读者的需要。

指南面向初学者,手册面向有经验的人和自己实现JNI 规范的人。

大部分读者可能是用JNI来写程序的开发者。

本书会假设你有JA V A,C/C++基础。

本章的剩余部分介绍了JNI的背景,扮演的角色和JNI的演化。

1.1 JA V A平台和系统环境(Host Environment)系统环境代指本地操作系统环境,它有自己的本地库和CPU指令集。

本地程序(Native Applications)使用C/C++这样的本地语言来编写,被编译成只能在本地系统环境下运行的二进制代码,并和本地库链接在一起。

本地程序和本地库一般地会依赖于一个特定的本地系统环境。

JNI技术在嵌入式软件开发中的应用学习笔记

JNI技术在嵌入式软件开发中的应用学习笔记

JNI技术在嵌入式软件开发中的应用学习笔记之一嵌入式系统是以应用为中心、以计算机技术为基础、软件硬件可裁剪、适应应用系统对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。

嵌入式软件的基本体系结构包括嵌入式实时操作系统RTOS(RealTime operating Systerrl)、嵌入式设备驱动程序、嵌入式应用程序编程接口(中间件)和嵌入式应用程序。

现阶段,计算机应用的普及、互联网技术的实用以及纳米微电子技术的突破,正有力推动着21世纪的工业生产、商业活动、科学实验和家庭生活等领域自动化和信息化进程。

全过程自动化产品制造、大范围电子商务活动、高度协同科学实验以及现代化家居生活,为嵌入式产品造就了崭新而巨大的商机。

除了沟通信息高速公路的交换机、路由器和调制解调器,构建计算机集成制造系统(CIMS)所需的数据传输系统DCS(Data Communication System)和机器人以及规模较大的家用汽车电子系统,最有产量效益和时代特征的嵌入式产品应数因特网上的信息家电(information appliances),如网络可视电话、网络游戏机、电子商务、商务通(PDA)、移动电话以及多媒体产品(如电视机顶盒、DVD播放机、电子阅读机)。

众所周知,“一次编程,到处使用”的Java 软件概念原本就是针对网上嵌入式小设备提出的,几经周折,目前SUN公司已推出了J2ME(Java 2 P1atform Micro Edition)针对信息家电的Java版本,其技术日趋成熟,开始投入使用。

SUN公司Java虚拟机(JVM)技术的有序开放,使得Java软件真正实现跨平台运行,即Java应用小程序能够在带有JVM的任何硬软件系统上执行。

加上Java 语言本身所具有的安全性、可靠性和可移植性等特点,对实现瘦身上网的信息家电等网络设备十分有利,同时对嵌入式设备特别是上网设备软件编程技术产生了很大的影响。

1 Java的性能问题及几种解决方案Java程序也有其本身的缺陷,那就是其效率问题。

JNI_笔记

JNI_笔记

获取构造函数:
1、获取构造函数的jmethodId:构造函数的方法名为<init>
jclass GetObjectClass(jobject obj)
jclass GetSuperClass(jclass obj)
FindClass绘制classpath系统环境变量下寻找类,传入完整类名,包与包使用/隔开
jclass cls_string=env->FindClass("java/lang/String");
JNIEnv* :JNIEnv类型实际上代表Java环境,通过该参数可以对Java端的代码进行操作。
获取属性、调用方法:NewObject/NewString/New<Type>Array type数据类型
Get/Set<Type>Field
Get/Set<Type>Field
Get/SetStatic<Type>Field
Call<Type>Method/CallStatic<Type>Method
jobject:代表Java对象的引用,如果是静态的field或method则该参数代表该类的Class对象,
否则为该类的实例,通过什么对象来调用本地代码的来判断。
long J
float F
double D
void V
object L用/分隔包的完整类名; Ljava/lang/String;
Array [签名 [I(获取int类型的数组) [Ljava/lang/object(获取object的数组);
Method (参数1类型签名 参数2类型签名...)返回值类型签名

Android JNINDK 学习笔记

Android JNINDK 学习笔记

Android JNI/NDK 学习笔记likunarmstrong@JNI,全称Java Native Interface,是用于让运行在JVM中的Java代码和运行在JVM外的Native代码(主要是C或者C++)沟通的桥梁。

代码编写者即可以使用JNI从Java的程序中调用Native代码,又可以从Native程序中调用Java代码。

这样,编程人员可以将低阶的代码逻辑包装到高阶的程序框架中,获得高性能高效率的同时保证了代码框架的高抽象性。

在Android中,仅有以下类库是允许在JNI中使用的:●libc (C library) headers●libm (math library) headers●JNI interface headers●libz (Zlib compression) headers●liblog (Android logging) header●OpenGL ES 1.1 (3D graphics library) headers (since 1.6)● A Minimal set of headers for C++ supportJNI本身仅仅是一个把两者融合的工具,作为编程者需要做的,就是在Java代码和Native代码中按照固定的格式告诉JNI如何调用对方。

在Android中,有两种方式可以调用JNI,一种是Google release的专门针对Android Native开发的工具包,叫做NDK。

去Android网站上下载该工具包后,就可以通过阅读里面的文档来setup一个新的包含Native代码的工程,创建自己的Android.mk文件,编译等等;另一种是完整的源码编译环境,也就是通过git从官方网站获取完全的Android源代码平台。

这个平台中提供有基于make的编译系统。

更多细节请参考这里。

不管选择以上两种方法的哪一个,都必须编写自己的Android.mk文件,有关该文件的编写请参考相关文档。

jni详解(中文翻译)

jni详解(中文翻译)

前言翻译初衷,记录JNI编程经验以备后查,并奢望以JNI为蓝本,写一本更深入的关于虚拟机的书。

真做起来,才发现以现有水平只能仰望这个目标,要达到它,还需要几年积累。

本书没有采用逐字逐句的翻译,更多采用意译,请大家在阅读时多参考原著;对于书中夹杂的评论,如有伤观感,请大家见谅。

现在有无数优秀的开源项目,以前高深莫测的技术(虚拟机、编译器、操作系统、协议栈和IDE...), 我们终于有机会一探究竟了,真令人兴奋。

我们学习,我们参与,希望有一天我们中国人也能创一门牛技术。

感谢Die...ken的审稿,他严谨和认真的态度,深感敬佩;哥们儿祝你:天天开心,早结连理。

感谢老婆。

老婆读书时,看见别人写的书总会感谢太太云云,煞是羡慕,总追问:你什么时候写书感谢我?难!翻译都这么费劲,写书就不知猴年马月了,在这儿感谢一下,糊弄糊弄得了。

do.chuan@Preface 本书涵盖了Java Native Interface(JNI)的内容,将探讨以下问题:•在一个Java项目中集成一个C/C++库•在一个用C/C++开发的项目中,嵌入JavaVM•实现Java VM•语言互操作性问题,特别是互操作过程中的垃圾回收(GC, garbage collection)和并发编程(multithreading)首先,通过本书,你会很容易的掌握JNI开发,并能了解到方方面面的关于JNI的知识。

本书详尽的叙述,会带给你你很多如何高效使用JNI的启示。

JNI自1997年初发布以来,Sun的工程师们和Java社区使用JNI的经验造就了本书。

第二,本书介绍了JNI的设计原理。

这些原理,不仅会使学术界感兴趣,也是高效使用JNI的前提。

第三,本书的某些部分是Java 2平台规范的最终版本。

JNI程序员可以此书作为规范的参考手册,Java虚拟机实现者必须遵循规范,以保证各平台实现的一致性。

(...几段不重要,未翻译...)C HA P T E R1IntroductionJNI是Java平台中的一个强大特性。

解析Java的JNI编程中的对象引用与内存泄漏问题

解析Java的JNI编程中的对象引用与内存泄漏问题

解析Java的JNI编程中的对象引⽤与内存泄漏问题JNI,Java Native Interface,是 native code 的编程接⼝。

JNI 使 Java 代码程序可以与 native code 交互——在 Java 程序中调⽤ native code;在 native code 中嵌⼊ Java 虚拟机调⽤ Java 的代码。

JNI 编程在软件开发中运⽤⼴泛,其优势可以归结为以下⼏点:利⽤ native code 的平台相关性,在平台相关的编程中彰显优势。

对 native code 的代码重⽤。

native code 底层操作,更加⾼效。

然⽽任何事物都具有两⾯性,JNI 编程也同样如此。

程序员在使⽤ JNI 时应当认识到 JNI 编程中如下的⼏点弊端,扬长避短,才可以写出更加完善、⾼性能的代码:从 Java 环境到 native code 的上下⽂切换耗时、低效。

JNI 编程,如果操作不当,可能引起 Java 虚拟机的崩溃。

JNI 编程,如果操作不当,可能引起内存泄漏。

JAVA 中的内存泄漏JAVA 编程中的内存泄漏,从泄漏的内存位置⾓度可以分为两种:JVM 中 Java Heap 的内存泄漏;JVM 内存中 native memory 的内存泄漏。

局部和全局引⽤JNI将实例、数组类型暴露为不透明的引⽤。

native代码从不会直接检查⼀个不透明的引⽤指针的上下⽂,⽽是通过使⽤JNI函数来访问由不透明的引⽤所指向的数据结构。

因为只处理不透明的引⽤,这样就不需要担⼼不同的java VM实现⽽导致的不同的内部对象的布局。

然⽽,还是有必要了解⼀下JNI中不同种类的引⽤:1)JNI ⽀持3中不透明的引⽤:局部引⽤、全局引⽤和弱全局引⽤。

2)局部和全局引⽤,有着各⾃不同的⽣命周期。

局部引⽤能够被⾃动释放,⽽全局引⽤和若全局引⽤在被程序员释放之前,是⼀直有效的。

3)⼀个局部或者全局引⽤,使所提及的对象不能被垃圾回收。

Android NDK学习笔记

Android NDK学习笔记

Android NDK学习笔记前言Android系统中的应用程序都是用Java开发的。

Android NDK使我们能够在android上使用C/C++开发的原生代码。

有两个理由使用NDK: 一是合理的重用现有的代码;二是在程序中某些关键的部分提高执行效率。

这里先讲几个符号的约定:<project> - 你的Android应用程序工程的目录<ndk> - 你的ndk安装的目录捷径这里先扯一句题外话-- 如果你不需要使用NDK开发,只是需要使用第三方用NDK开发的库,那么你只需要这样做:把第三方提供的libxxx.so放到你的<project>/libs/armeabi/下,然后在程序随便什么地方中加入static {System.loadLibray("xxx");}就可以使用该库了。

安装NDKNDK的安装很简单:1. 首先要将SDK升级至最新,然后下载ndk(可能要翻墙,恩恩)将它解压到某个目录<ndk>下。

2. 运行:<ndk>/build/host-setup.sh3. 如果成功的话就OK了,如果失败的话检查一下你是不是下载了正确的ndk版本(例如你的操作系统是linux而下载了windows版的ndk).Java部分现在我们用一个很简单的例子来说明NDK的使用。

我们在eclipse中新建一个android工程,其中:Project Name:jnitestBuild Target: Android 1.6Application Name: JNI TestPackage Name: org.eshock.jnitestCreate Activity: JNITestJNITest.java:package org.eshock.jnitest;import android.app.Activity;import android.os.Bundle;public class JNITest extends Activity {public native int plus (int x, int y);/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);int x = plus(1, 2);android.util.Log.d("jni", String.valueOf(x));}static {System.loadLibrary("mylib");}}我们只是演示NDK,所以就不要界面了。

jni面试题

jni面试题

jni面试题JNI(Java Native Interface)是Java编程语言的一种编程框架,用于在Java虚拟机(JVM)中调用本地代码,实现Java与其他编程语言(如C++、C等)的互操作性。

在JNI面试中,面试官往往会提出一些相关问题来考察面试者对JNI的理解和应用能力。

本文将介绍一些常见的JNI面试题,并提供相应的解答,希望对您进一步了解JNI有所帮助。

一、什么是JNI以及其作用?JNI全称为Java Native Interface,是Java提供的一种编程框架,用于实现Java与其他编程语言之间的互操作性。

它允许Java代码调用本地代码(如C++、C等编写的代码),从而可以让Java程序访问底层操作系统和硬件资源,提高了Java程序的灵活性和性能。

二、JNI的工作原理是怎样的?在Java程序中调用本地方法时,JNI首先会通过Java Native Method (JNI规范定义的接口)将Java代码与本地代码连接起来。

然后,通过JNI函数将Java参数传递给本地方法,在本地方法中执行相关的操作,并将结果返回给Java程序。

最后,Java程序可以继续执行后续逻辑。

三、如何使用JNI实现Java与C++的互相调用?1. 编写Java类:在Java类中声明native方法,并且加载C++动态链接库。

public class MyClass {public native void myMethod();static {System.loadLibrary("myLibrary");}}```2. 生成C++头文件:使用`javac`命令生成C++头文件(`.h`文件)。

```javac -h . MyClass.java```3. 编写本地C++代码:实现在Java类中声明的native方法。

```#include <jni.h>#include "MyClass.h"JNIEXPORT void JNICALL Java_MyClass_myMethod(JNIEnv* env, jobject obj) {// 执行相关操作```4. 编译C++代码:将C++源代码编译为动态链接库,供Java程序调用。

jni必学C语言基础

jni必学C语言基础

Eclipse是用纯Java语言开发出来的IDE工具system( )方法system("pause"); //调用windows cmd里面的pausesystem( )以就是用来调用windows cmd里的命令,如在.c 源文件的目录下放一个Java的类如aa.class (这个类的main方法输出一个”hello”),则我们可以在.c源文件中用:system(“java aa”);来运行这个java类,就相当于在cmd命令行窗口输入:java aa一样的效果,所以当把C生成的exe文件拷到其他地方的时候,默认会找与exe文件所在目录的aa.class,这时就会出现找不到的情况,在cmd命令行输入javac,查看帮助,可以看到-classpath <路径>,所以在C语言中可也用这个语句:system("java -classpath C:/ a");C的基本数据类型// 在c99标准的c语言.没有byte 类型没有boolean 类型// 在c语言里面0表示的是假非0表示的是真// c语言中的char的长度和java中的byte的长度相同,所以可以用c 语言中的char类型表示java中的byte类型// c语言中的int 和java中的int在内存中的长度相同所以java的int 和c语言中的int 可以互相代替使用.C语言输出printf( )int i=5;printf("int i = %d \n",i);%d - int%ld –long int%c - char%f - float%u –无符号数%hd –短整型%lf –double%x –十六进制输出int 或者long int 或者short int%#x十六进制输出,#的作用就是在16进制的前面加上“0x”%o - 八进制输出%s –字符串如果把字符‘A’按照%d格式输出那么就是:65如果把int型的354353453用short型输出,结果为301,分析图如下:C语言输入scanf( )int i; //注:C语言中的变量可以不初始化scanf("int i = %d \n",&i); //&i 取i变量的地址//第一个参数是数据以什么样子的类型接受到程序里面// 第二个参数数据存放到哪一块内存空间里面//& 取地址可以获取某个变量在内存中的地址c语言里面是没有String类型// c语言表示一个字符串,可定义一个字符的数组// 利用scanf %s 的方式可以方便的从键盘获取一个字符串,如:char arr[10]={'h','e','l','l','o'};printf("s = %s\n",arr); //打印字符数组scanf("%s",arr); //利用字符数组接收一个字符串Java语言中输入一个字符串public static void main(String[] args) throws IOException {BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); String str = stdin.readLine();System.out.println(str);}}c语言输入一个字符串char c[20] ;scanf("%s",c);printf("输入的是%s \n",c);指针入门指针和指针变量的关系●指针就是地址,地址就是指针●地址就是内存单元的编号●指针变量是存放地址的变量●指针和指针变量是两个不同的概念●但是要注意:通常我们叙述时会把指针变量简称为指针,实际它们含义并不一样为什么使用指针●指针的重要性●直接访问硬件(opengl 显卡绘图)●快速传递数据(指针表示地址)●返回一个以上的值(返回一个数组或者结构体的指针)●表示复杂的数据结构(结构体)●方便处理字符串●指针有助于理解面向对象*号的三种含义1.乘法3*52.定义指针变量int * p;//定义了一个名字叫p的变量,能够存放int数据类型的地址3.指针运算符,如果p是一个已经定义好的指针变量,则*p表示以p的内容为地址的变量32位的XP操作系统能表示的最大内存是:2的32次方,用这个值除1024/1024/1024 = 4G,所以32位的操作系统支持的最大内存是4G// 指针代表的就是一个内存地址. 内存地址可以用一个指针来表示.// 地址就是一块内存空间的编号,通过这个编号我们可以使用以一块内存空间.int i = 3; //在内存里面申请了一块内存,这块内存是可以存放一个int类型的数据(4个字节)// 指针变量: 可以存放指针类型(内存地址数据)数据的变量指针变量.// 使用* 来表示指针变量.// int* 代表的就是一个表示int类型数据地址的变量int* p; // 定义一个变量,变量的名字叫p ,里面可以存放一个int* 类型的数据,int* 代表的就是一个int变量的地址.编写一个连连看实例main(){printf("连连看60秒倒计时开始\n");int count = 60;int* p = &count; //打印count的内存地址printf("count的内存地址为:%#x\n",p);while(count>0){printf("%d\n",count);sleep(2000);count--;}}安装CheatEngine561.exe软件cheat [tʃi:t] 欺骗;作弊Engine引擎,发动机1、运行连连看2、点打开连连的进程先在Value处输一下值,等连连看的倒数到这个值是点击“New Scan”Cmd里打印出的内存地址为,在CheatEngine软件的找到对应的地址并双击,然后再双击:这时可以改变这个内存地址的值为100,则连看的倒计时又从100开始了。

JNI官方规范中文版——如何访问Java中的字段和方法

JNI官方规范中文版——如何访问Java中的字段和方法

JNI官方规范中文版——如何访问Java中的字段和方法现在,你知道了如何通过JNI来访问JVM中的基本类型数据和字符串、数组这样的引用类型数据,下一步就是学习怎么样和JVM中任意对象的字段和方法进行交互。

比如从本地代码中调用JAVA中的方法,也就是通常说的来自本地方法中的callbacks(回调)。

我们从进行字段访问和方法回调时需要的JNI函数开始讲解。

本章的稍后部分我们会讨论怎么样通过一些cache(缓存)技术来优化这些操作。

在最后,我们还会讨论从本地代码中访问字段和回调方法时的效率问题。

4.1 访问字段JAVA支持两种field(字段),每一个对象的实例都有一个对象字段的复制;所有的对象共享一个类的静态字段。

本地方法使用JNI提供的函数可以获取和修改这两种字段。

先看一个从本地代码中访问对象字段的例子:class InstanceFieldAccess {private String s;private native void accessField();public static void main(String args[]) {InstanceFieldAccess c = new InstanceFieldAccess();c.s = "abc";c.accessField();System.out.println("In Java:");System.out.println(" c.s = \"" + c.s + "\"");}static {System.loadLibrary("InstanceFieldAccess");}}InstanceFieldAccess这个类定义了一个对象字段s。

main方法创建了一个对象并设置s的值,然后调用本地方法InstanceFieldAccess.accessField在本地代码中打印s的值,并把它修改为一个新值。

Java JNI详细学习教程

Java JNI详细学习教程

一、Java调用C/C++代码一、什么是JNIJava Native Interface(JNI)是Java语言的本地编程接口是 Java 与操作系统本地代码互相调用的功能的接口二、Java 调用C/C++步骤:1、在Java类中声明native方法新建一个Java 工程T estNativeCode 包 com.fomagic 类T estnative package com.fomagic;public class T estNative {public native void sayHello(); //C++本地代码实现public static void main(String[] args) {}}2、使用javah命令生成包含native方法定义的C/C++头文件3、按照生成的C/C++头文件来写C/C++ 源文件1) 在VS 中新建 Win32控制台应用程序–> 确定–> 下一步(即选择应用程序设置)2) 拷贝三个文件到项目目录下com_fomagic_T estNative.h 第2步生成的头文件jni.h 位于JDK 下的 include 文件目录中jni_md.h include—>win32 目录3) 添加现有项 com_fomagic_T estNative.h 引入头文件(如图)4) 新建源文件source.cpp 添加如下内容5) 注意引用的头文件“ <> ”代表从系统查找、“” “” 优先从本地查找#include "com_fomagic_T estNative.h"#include <iostream>;using namespace std;//对com_fomagic_T estNative.h 中声明的方法定义JNIEXPORT void JNICALL Java_com_fomagic_T estNative_sayHello (JNIEnv *evn, jobject obj){cout<<"Hello World !"<<endl;}4、将C/C++源文件编译成动态链接库(DLL)可执行二进制代码执行生成解决方案,在项目目录下的Debug 生成 DLL 文件5、把DLL文件所在路径添加到PATH环境变量下这个配置过Java环境变量的都应该是清楚的,这样可以方便Java程序直接调用当前的动态链接库注意:需要注意的是Eclipse开发Java程序需要重启来重新加载环境变量6、java 类中加载DLL,然后调用声明的native方法package com.fomagic;public class T estNative {public native void sayHello(); //C++本地代码实现public static void main(String[] args) {System.loadLibrary("NativeCode"); //加载动态链接库,不能加 .dllT estNative test=new T estNative();test.sayHello();}}7、运行Java 项目1) 执行结果: Hello World !2) 异常信息:Can’t load IA 32-bit .dll on a AMD 64-bit platform(大概意思就是64位的AMD 平台不能加载32 位的 .dll 文件)解决办法请百度三、弊端及注意点使用JNI,这个java Application 将不能跨平台,如果要移植到别的平台上,则 native代码需要重新进行编写java是强类型语言,而C/C++则不是,因此,必须在写JNI时更加小心在构建java程序的时候,尽量少用本地代码二、C++访问Java代码-知识点第二讲主要是介绍JNI中提供的调用和修改以及其他一些操作java代码的方法,具体如下1、Java工具生成的C/C++函数声明中,可以看到两个参数://对com_fomagic_T estNative.h 中声明的方法定义JNIEXPORT void JNICALL Java_com_fomagic_T estNative_sayHello (JNIEnv *evn, jobject obj){cout<<"Hello World !"<<endl;}JNIEnv *envJNIEnv类型可以看做是Java环境,通过这个JNIEnv* 指针,可以对Java端的代码进行操作,JNIEnv的指针会被JNI传入到本地方法的实现函数中来对Java端的代码操作例如:创建Java类的对象,调用Java对象的方法,获取Java对象的属性等<TYPE> 代表数据类型函数:NewObject/NewString/New<TYPE>Array //创建数组Get/Set<TYPE>Field //获取/设定变量属性Get/SetStatic<TYPE>Method/CallStatic<TYPE>Method … //对方法进行操作我们可以在jni.h 头文件中找到所有定义的方法:struct JNIEnv_; //定义所有方法的结构体typedef JNIEnv_ JNIEnv;………………struct JNIEnv_ {const struct JNINativeInterface_ *functions;………………jclass FindClass(const char *name) {return functions->FindClass(this, name);}………………jint GetIntField(jobject obj, jfieldID fieldID) {return functions->GetIntField(this,obj,fieldID);}}jobject obj同样也可以在jni.h 中看到对jobject 的定义表示传进来的参数为调用该方法的对象,如果是 静态native 函数,则表示native 方法坐在的类1 2 class _jobject {};typedef _jobject *jobject; //定义_jobject 类型别名 为 jobject2、Java 类型在C/C++中的映射关系这个没有什么要说的,直接看图,就是JNI 为了我方便使用定义的别名3、jclass的取得为了可以在C/C++中使用Java类jni.h头文件中专门定义了jclass类型来表示Java 中的Class类JNIEnv类中有如下几个函数取得jclassjclass FindClass(const char* clsName);jclass GetObjectClass(jobject obj);jclass GetSuperClass(jclass obj);FindClass会在classpath系统环境变量下找类传入完整类名,注意包与包之间用”/” 而不是”.”来连接如:jclass cls_string=env->Fin dClass(“java/lang/String”);4、访问Java类中的属性和方法在C/C++本地代码中访问Java端的代码,一个常见的应用就是获取类的属性和调用类的方法,为了在C/C++中表示属性和方法,JNI在jni.h 头文件中定义了jfieldID、jmethodID 类型来分别代表Java端的属性和方法在访问设置Java 属性和方法时,首先在本地代码获取代表Java属性的jfieldID 和jmethodID 然后进行Java属性和方法的操作JNIEnv中 GetFieldID/GetMethodID GetStaticFieldID/GetStaticMethodID 获取如:env->GetMethodID(data_Clazz,”<int>”,”()V”); // ()V指无返回类型void,下面讲到5、Sign是什么?例如T estNative.java中有两个重载方法:package com.fomagic;public class T estNative {public void function(int i){System.out.println("Integer: "+i);}public void function(double d){System.out.println("Double: "+d);}}当在C++中调用其中一个函数的时候,就需要按照以下步骤:获取函数所在类jclass clazz_T estnative=env->FindClass(“com/fomagic/T estNative”);2、获取方法的jmethodID 来调用方法jmethodID id_func =env->GetMethodID (clazz_T estnative,”function”,” (I)V”);->GetMethodID (clazz_T estnative,”function”,”(D)V”);其中通过指定函数的参数类型和返回值类型来返回jmethodID,从而对应的函数,这就是sign以下是对应类型:6、使用javap命令生成签名JDK中提供了javap工具来查看类的声明,可以输出每个方法与属性的签名package com.fomagic;import java.util.Date;public class T estNative {public native void sayHello(); //C++本地代码实现public static void main(String[] args) {System.loadLibrary("NativeCode");//加载动态链接库,不能加.dllT estNative test=new T estNative();test.sayHello();}public int property;public int function(int foo,Date date, int[] arr){return 0;}}我们对上面代码通过javap 工具直接生成方法和属性的签名:1、命令行定位到该类的绝对路径 cd T estNativeCode\bin 目录2、执行javap -s -private com.fomagic.T estnativejavap -s -p… [完整类名]注:private获取全部权限的成员、public获取public修饰的成员 (即获取大于或等于自己权限的成员方法或属性)三、C++操作java属性和方法在第二讲中讲到了C++中操作java程序的方法以及操作步骤,下面就通过实例的方式来体会到底怎么通过JNI提供的方法来获取、操作java属性、方法以及父类方法1、取得/设定Java属性值在原来java 类T estNative的基础上编写如下代码:package com.fomagic;public class T estNative {public native void sayHello(); //C++本地代码实现public int number=10; //定义变量初始值为10,在C++中进行修改public static void main(String[] args) {System.loadLibrary("NativeCode");//加载动态链接库,不能加.dllT estNative test=new T estNative(); //创建本类实例test.sayHello();System.out.println("C++中操作之后的结果:"+test.number);}}C++中原有代码添加如下:JNIEXPORT void JNICALL Java_com_fomagic_T estNative_sayHello (JNIEnv *env, jobject obj){cout<<"Hello World !"<<endl;jclass clazz_T estNative=env->GetObjectClass(obj); //通过传入的obj类的对象获取当前类jfieldID id_number=env->GetFieldID(clazz_T estNative,"number","I"); //类实例,属性名,(sign)数据类型jint number =env->GetIntField(obj,id_number); // 通过ID 获取当前变量cout<<"原数据:"<<number <<endl;env->SetIntField(obj,id_number,100L); //类实例,变量ID, 修改的java属性值}注:修改的属性值100L,可以参看第二讲的“Java类型在C/C++中的映射关系” 图表(java中 int 对应C++中long)2、调用Java类的方法调用实例方法的三种形式;Call<TYPE>Method(jobject obj ,jmethodID id ,….);Call<TYPE>MethodV(jobject obj ,jmethodID id ,va_list lst);Call<TYPE>Method(jobject obj ,jmethodID id ,jvalue* v) ;第一个比较常用第二个是当调用这个函数有一个指向参数表的va_list变量时使用(只知道是可变参数列表) 第三个当调用函数时有一个指向jvalue或jvalue数组的指针时使用(即传入的是所有参数的变量数组指针)下面就以第一种方式写下返回较大值的实例:package com.fomagic;public class T estNative {public native void sayHello(); //C++本地代码实现public static void main(String[] args) {System.loadLibrary("NativeCode");//加载动态链接库,不能加.dllT estNative test=new T estNative();test.sayHello();}double max(double num1,double num2){return num1>num2 ? num1 : num2;}}JNIEXPORT void JNICALL Java_com_fomagic_T estNative_sayHello (JNIEnv *env, jobject obj){jclass clazz_T estNative=env->GetObjectClass(obj); //获取当前类jmethodID id_max=env->GetMethodID(clazz_T estNative,"max","(DD)D"); //获取方法ID(签名)jdouble maxValue = env->CallDoubleMethod(obj,id_max,100.5,203.1); //调用max方法进行传值cout<<"较大值:"<<maxValue <<endl; }3、调用Java类父类方法我们都知道在java中父类创建子类对象只能调用子类的覆盖方法,而C++中子类对象默认调用的父类的方法,当父类方法用虚拟函数关键字virtual修饰时,调用子类覆盖方法通过JNI的 CallNonvirtual<TYPE>Method 可以实现子类对象调用父类被覆盖的方法的功能,步骤:取得父类和需要调用的父类中方法的jmethodID将jmethodID传入 CallNonvirtual<TYPE>Method代码:新建Father类、Child类package com.fomagic;public class T estNative {public native void sayHello(); // C++本地代码实现public Father p=new Child(); //创建Child 的实例对象public static void main(String[] args) {System.loadLibrary("NativeCode");// 加载动态链接库,不能加 .dllT estNative test = new T estNative();test.sayHello();}}class Father {public void function() {System.out.println("Father function");}}class Child extends Father {public void function() {System.out.println("Child function");}}JNIEXPORT void JNICALL Java_com_fomagic_T estNative_sayHello (JNIEnv *env, jobject obj){jclass clazz_T estNative=env->GetObjectClass(obj);jfieldID id_p=env->GetFieldID(clazz_T estNative,"p","Lcom/fomagic/Father;");jobject p= env->GetObjectField(obj,id_p);jclass clazz_Father = env->FindClass("com/fomagic/Father");jmethodID id_Father_function= env->GetMethodID(clazz_Father,"function","()V");//env->CallVoidMethod(p,id_Father_function);;env->CallNonvirtualVoidMethod(p,clazz_Father,id_Father_function);}四、(1)在C++中创建Java对象本节讲的是在C/C++本地代码中创建Java对象,JNI 中提供两个方法进行Java对象的操作,分别是 NewObject 和 Allocobject,先看下jni.h 头文件中对两个方法的定义jobject NewObject(jclass clazz, jmethodID methodID, ...) {va_list args;jobject result;va_start(args, methodID);result = functions->NewObjectV(this,clazz,methodID,args);va_end(args);return result;}jobject AllocObject(jclass clazz) {return functions->AllocObject(this,clazz);}1、NewObject 创建Java对象GetMethodID 能够获取构造方法的jmethod,如果传入的要取得的方法名称设定为”<init>”就能取得构造方法构造方法没有返回值,签名始终为Void (()V)下面是一个通过C++创建Java的Date对象并在Java控制台输出1970到现在毫秒数package com.fomagic;public class T estNative {public native void sayHello(); // C++本地代码实现public static void main(String[] args) {System.loadLibrary("NativeCode");// 加载动态链接库,不能加 .dllT estNative test = new T estNative();test.sayHello();}}JNIEXPORT void JNICALL Java_com_fomagic_T estNative_sayHello (JNIEnv *env, jobject obj){jclass clazz_date = env->FindClass("java/util/Date"); //找到Date类jmethodID id_date= env->GetMethodID(clazz_date,"<init>","()V"); //通过类获取构造方法ID,默认无返回值jobject now=env->NewObject(clazz_date,id_date); //创建Date的实例对象jmethodID id_date_getTime=env->GetMethodID(clazz_date,"getTime","()J"); //获取Date类的getTime()方法的ID,返回值是long 即JNI中对应的J jlong time = env->CallLongMethod(now,id_date_getTime); //通过now对象调用getTime()方法,得到时间cout<<time<<endl;}代码很简单通过前面的知识都是可以明白的,注释应该没什么问题(吧)2、Allocobject创建Java对象使用函数AllocObject 可以根据传入的jclass创建一个Java对象但他的状态是非初始化的,在使用这个对象之前绝对要用CallNovirtualVoidMethod来调用该jclass的建构函数,这样可以延迟构造函数的调用,这一部分用的很少(对于这个函数到底是什么意思,我也没有完全搞明白,只是知道这样用,以后慢慢研究) jclass clazz_str =env->FindClass("java/lang/String");jmethodID methodID_str=env->GetMethodID(clazz_str,"<init>","([C)V");//获取构造jObject string =env->AllocObject(clazz_str);// 预先创建没有初始化的字符串jcharArray arg=env->NewCharArray(4); //创建长度为4的字符数组env->SetCharArrayRegion(arg,0,4,L"奇幻未来"); //复制"奇幻未来"到数组arg中env->CallNonvirtualVoidMethod(string,clazz_str,methodID_str,arg); //讲arg字符数组复制给stringjclass clazz_this=env->GetObjectClass(obj);// 这是视频中假设这个对象的类中有定义static String STATIC_STR;jfieldIDfieldID_str=env->GetStaticFieldID(clazz_this,"STATIC_STR","Ljava/lang/String;"); env->SetStaticObjectField(clazz_str,fieldID_str,string);四、(2)C++访问Java的String字符串对象我以前是学Java的,对于C++只是明白很少的知识,所以看得越多,出现的问题也越多,我只有慢慢消化了第四讲的第二部分:在C/C++本地代码中访问Java的String字符串对象Java与C++中字符串的区别在Java中,使用的字符串String 对象时Unicode(UTF-16)码,即每个字符不论是中文还是英文还是符号,一个字符总是占两个字节Java通过JNI接口可以将Java的字符串转换到C/C++的宽字符串(wchar_t*),或是传回一个UTF-8的字符串(char*)到C/C++.C/C++可以通过一个看字符串或是一个UTF-8编码的字符串来创建一个Java端的String对象JNI中操作字符串相关函数函数作用是取得某个jstring对象相关的Java字符串,介绍了三种类型的字符串操作函数1、GetStringChars 与 GetStringUTFCharsGetStringChars 取得UTF-16编码的宽字符串(jchar*)GetStringUTFChars 取得UTF-8编码的字符串(char*)const jchar *GetStringChars(jstring str, jboolean *isCopy) {return functions->GetStringChars(this,str,isCopy);}const char* GetStringUTFChars(jstring str, jboolean *isCopy) {return functions->GetStringUTFChars(this,str,isCopy);}void ReleaseStringChars(jstring str, const jchar *chars) {functions->ReleaseStringChars(this,str,chars);}void ReleaseStringUTFChars(jstring str, const char* chars) {functions->ReleaseStringUTFChars(this,str,chars);}1 )、参数第一个参数传入一个指向Java中的String对象的jstring变量.第二个参数传入jboolean 指针,标示是否对Java的String对象进行了Copy。

详解AndroidJNI的基本使用(CMake)

详解AndroidJNI的基本使用(CMake)

详解AndroidJNI的基本使⽤(CMake)简介什么是JNIJNI的全称是Java Native Interface:Java本地开发接⼝,它提供了若⼲的API实现了Java和其他语⾔的通信(主要是C和C++),⽬的就是Java可以调⽤C或C++开发的函数,C或C++也能调⽤Java的⽅法。

这样有很多有点,其⼀就是效率,C/C++是本地语⾔,⽐java更⾼效;其⼆就是可以复⽤已经存在的C/C++代码;其三是Java反编译⽐C语⾔容易,⼀般加密算法都是⽤C语⾔编写,不容易被反编译。

什么是NDK和CMakeNDK全称是Native Development Kit,NDK提供了⼀系列的⼯具,帮助开发者快速开发C(或C++)的动态库,并能⾃动将so和Java应⽤⼀起打包成apk。

NDK集成了交叉编译器,并提供了相应的mk⽂件隔离CPU、平台、ABI等差异,开发⼈员只需要简单修改mk⽂件(指出“哪些⽂件需要编译”、“编译特性要求”等),就可以创建出so。

CMake是⼀个⽐make更⾼级的编译配置⼯具,它可以根据不同平台、不同的编译器,⽣成相应的Makefile或者vcproj项⽬。

通过编写CMakeLists.txt,可以控制⽣成的Makefile,从⽽控制编译过程。

CMake⾃动⽣成的Makefile不仅可以通过make命令构建项⽬⽣成⽬标⽂件,还⽀持安装(make install)、测试安装的程序是否能正确执⾏(make test,或者ctest)、⽣成当前平台的安装包(make package)、⽣成源码包(make package_source)、产⽣Dashboard显⽰数据并上传等⾼级功能,只要在CMakeLists.txt中简单配置,就可以完成很多复杂的功能,包括写测试⽤例。

如果有嵌套⽬录,⼦⽬录下可以有⾃⼰的CMakeLists.txt。

使⽤流程1、在java⽂件中创建本地⽅法2、build项⽬后⾃动⽣成“.h”⽂件3、创建.cpp⽂件,实现.h⽂件中的⽅法4、配置Cmake⽂件,⽣成“.so”⽂件笔者项⽬⽬录如下:测试实例public class MyJNI {private static final String TAG=MyJNI.class.getName();@Testpublic void test(){JNITest jniTest=new JNITest();Log.d(TAG,jniTest.nativeCalculate(2)+"");}}1、调⽤native⽅法nativeCalculate,传⼊参数2。

JNI 返回结构体参数

JNI 返回结构体参数

JNI 返回结构体参数jni返回结构体参数jnijavacc++c#如何使用jni的一些基本方法和过程在网上多如牛毛,如果你对jni不甚了解,不知道jni是做什么的,如何建立一个基本的jni程序,或许可以参考下面下面这些文章:利用vc++6.0实现jni的最简单的例子jni入门教程之helloworld篇sunjnitutorial在这些材料的例子中,大多数只是输入一些简单的参数,而没有获得任何参数。

在实际使用过程中,经常需要对参数进行处理和转换。

可以被C/C++程序识别。

例如,我们在C++中有一个结构diskinfo,它需要传递一个类似于diskinfo*pdiskinfo的参数。

如何将类似于C++的参数传递给Java?让我们讨论一些常见参数从C++到Java方法的转换:定义nativejava类:如果你习惯了使用jni,你就不会觉得它难了。

既然本地方法是由其他语言实现的,它们在java中没有函数体。

但是,所有本地代码必须用本地关键词声明,成为java类的成员。

假设我们在c++中有这么一个结构,它用来描述硬盘信息:Java代码1//硬盘信息2结构{3.charname[256];4.intserial;5.}diskinfo;那么我们需要在java中定义一个类来与之匹配,声明可以写成这样:Java代码1 Classdiskinfo{2//名称3.Publicstringname;4.5//序列号6.Publicintserial;7.}在这个类中,申明一些native的本地方法,来测试方法参数的传递,分别定义了一些函数,用来传递结构或者结构数组,具体定义如下面代码:Java代码1/***************************************************************/2//输入常用的数字类型(布尔、字节、字符、短、整数、浮点、双精度)3 publicnativevoiddisplayparms(stringshowtext、inti、booleanbl);4.5.// 调用静态方法6 publicnativentadd(inta,intb);7.8.// 输入数组9 publicnativevoidsetarray(布尔[]bllist);10.11.// 返回字符串数组12 publicnativestring[]getstringarray();13.14.// 返回一个结构15 publicnativediskinfogetstruct();16.17.// 返回结构数组18 publicnativediskinfo[]getstructarray();编译生成c/c++头文件定义Java类之后,下一步是编写本地代码。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

JNI学习笔记作者:叶乔生日期:2010-04-23参考资料:《Android JNI详述》《Java本地接口规范》《传智播客视频教程》笔记目录 (1)前述:JNI简介 (2)一,何时使用JNI (2)二,使用JNI的弊端 (2)三,基本工具的配备 (2)第一章:设计概述 (2)一,JNI 接口函数和指针 (2)二,本地方法的加载 (3)三,本地方法的定义 (3)四,JNI本地方法的流程 (3)第二章:HelloWord小程序 (3)一,创建Java工程 (4)二,使用javah生成头文件 (4)三,本地方法的C/C++编程 (5)四,制作so动态库文件 (5)第三章:JNI 类型和数据结构 (6)一,JNI类型和数据结构 (6)二,类型签名 (7)第四章:JNI 函数 (7)一,JNIEnv简介 (7)二,常用的API简介 (7)终结章:总结 (11)一,注意的地方 (11)二,内存泄露问题 (11)三,多线程的调用 (12)四,学习总结 (12)笔记目录前述:JNI简介第一章:设计概述第二章:HelloWord小程序第三章:JNI 类型和数据结构第四章:JNI 函数终结章:总结前述:JNI简介JNI 是本地编程接口。

它使得在Java 虚拟机(VM) 内部运行的Java 代码能够与用其它编程语言(如C、C++ 和汇编语言)编写的应用程序和库进行互操作。

JNI 最重要的好处是它没有对底层Java 虚拟机的实现施加任何限制。

因此,Java 虚拟机厂商可以在不影响虚拟机其它部分的情况下添加对JNI 的支持。

程序员只需编写一种版本的本地应用程序或库,就能够与所有支持JNI 的Java 虚拟机协同工作。

一,何时使用JNI1,标准Java 类库不支持与平台相关的应用程序所需的功能。

2,已经拥有了一个用另一种语言编写的库,而又希望通过JNI 使Java 代码能够访问该库。

3,想用低级语言(如汇编语言)实现一小段时限代码。

二,使用JNI的弊端1、如果本地接口要移植到其他平台,那么这些接口就需要重新编写。

2、Java是强类型的语言,而C/C++不是。

因此,你必须在使用JNI时更小心。

3、使用Java开发程序时,尽量少用本地代码。

三,基本工具的配备1,cygwin的安装2,NDK的安装(/build/host-setup.sh)第一章:设计概述一,JNI 接口函数和指针平台相关代码是通过调用JNI 函数来访问Java 虚拟机功能的。

JNI 函数可通过接口指针来获得。

接口指针是指针的指针,它指向一个指针数组,而指针数组中的每个元素又指向一个接口函数。

每个接口函数都处在数组的某个预定偏移量中。

下图说明了接口指针的组织结构。

JNI 接口的组织类似于C++ 虚拟函数表。

使用接口表而不使用硬性编入的函数表的好处是使JNI 名字空间与平台相关代码分开。

虚拟机可以很容易地提供多个版本的JNI 函数表。

JNI 接口指针只在当前线程中有效。

因此,本地方法不能将接口指针从一个线程传递到另一个线程中。

实现JNI 的虚拟机可将本地线程的数据分配和储存在JNI 接口指针所指向的区域中二,本地方法的加载1,首先将已经编译好的―.so‖文件拷贝到工程目录下。

2,程序中通过System.loadLibrary(―库名‖)方法来加载这些动态连接库。

―库名‖必须与―.so‖文件名一致,且不需要后坠名,JA V A会自动去识别是哪种类型三,本地方法的定义关键字―native‖来区分是否是本地方法接口,如:static native void Init_JNI(int nTime);public native void Init_JNI (int nTime);四,JNI本地方法的流程1,定义本地方法接口2,用javah生成对应的头文件3,编写C/C++代码4,制作―.so‖库文件5,加载并引用―.so‖库文件第二章:HelloWord小程序首先我们从一个简单的HelloWord小程序开始吧一,创建Java工程在Java上创建HelloWord工程,并定义本地方法,如下创建一个Hello类package HelloWord.JNI.TEST;public class Hello{static{System.loadLibrary("myjni");}static native String sayHello();}类中定义了一个静态的sayHello的本地方法。

―myjni‖是我们将要生成的库文件,即―myjni.so‖文件。

这样,应用就可以直接调用这个本地方法进行使用了。

二,使用javah生成头文件格式如:javah -classpath . -jni 包名.类名1,进入工程中的BIN目录下2,javah -classpath . -jni HelloWord.JNI.TEST.Hello这样,就生成了该本地方法的头文件―HelloWord_JNI_TEST_Hello.h‖,其中我们可以看到对本地方法的定义如下:/** Class: HelloWord_JNI_TEST_Hello* Method: sayHello* Signature: ()Ljava/lang/String;*/JNIEXPORT jstring JNICALL Java_HelloWord_JNI_TEST_Hello_sayHello (JNIEnv *, jclass);我们可以看到他的函数名是―Java_包名_类名_本地方法名‖JNIEnv参数是其自变量——它是指向类型为JNIEnv_的一个特殊JNI数据结构的指针。

JNI数据结构的一个元素是指向由JVM生成的一个数组的指针;该数组的每个元素都是指向一个JNI函数的指针。

Jclass是该―Hello类‖。

如果我们的本地方法定义的是―public‖的话,那这个参数就会变成―jobject‖,即其―Hello 对象‖;在Java中,所有被定义为静态的方法,是与非静态分开的,有固定的自有内存存储,而且都不允许访问非静态的方法(因为非静态的方法需要先创建对象),所以这里的入参是―类‖,而不是―对象‖。

三,本地方法的C/C++编程1,创建一个动态连接库的仿真工程2,创建―HelloWord_JNI_TEST_Hello .CPP‖文件,最好同头文件同名,容易区分。

3,编写简单的C/C++代码,如下:JNIEXPORT jstring JNICALL Java_HelloWord_JNI_TEST_Hello_sayHello(JNIEnv *env, jclass cls){//返回字符串―Hello, Welcome!‖return env->NewStringUTF("Hello, Welcome!");}四,制作so动态库文件我们将编写好的CPP文件,存放在NDK目录下的―apps\HelloWord‖目录下,然后创建makefile文件,―Application.mk‖和―Android.mk‖。

1,Application.mk代码为:#当前模块的名字叫做HelloWordAPP_MODULES := HelloWord#工程路径是当前目录APP_PROJECT_PA TH := $(call my-dir)# Android.mk的位置APP_BUILD_SCRIPT := $(call my-dir)/Android.mk2,Android.mk代码为:# Test that LOCAL_CFLAGS works for both C and C++ sources#本地路径为当前目录LOCAL_PATH := $(call my-dir)include $(CLEAR_V ARS)#编译的目标对象LOCAL_MODULE := HelloWord#编译的源文件LOCAL_SRC_FILES := HelloWord_JNI_TEST_Hello.cpp#需要包含的头文件目录LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)#是否需要prelink处理LOCAL_PRELINK_MODULE := false#指明要编译成动态库include $(BUILD_SHARED_LIBRARY)3,编译so动态库文件打开cygwin,在NDK目录下,执行―make APP=HelloWord -B‖即可。

这样我们便生成了libs目录,里面包含一个so动态库文件。

4,加载动态连接库把我们生成的整个libs文件夹,拷贝到android工程目录下,然后在eclipse中更新工程,这是我们便可以看到这个libs了,run一下,我们就能看到调用―sayHello‖这个本地方法返回的字符串了。

第三章:JNI 类型和数据结构一,JNI类型和数据结构首先大家来看这张表,如下图:二,类型签名JNI 使用Java 虚拟机的类型签名表述。

表3-2 列出了这些类型签名。

例如,Java 方法:long fun(int n, String s, int[] arr);具有以下类型签名:(ILjava/lang/String;[I)J一,查询类型签名方法JDK提供了一个工具javap来查看一个类的方法的签名javap –s –p [full Class Name](即:包名.类名)-s 表示输出签名信息-p 同-private, 输出包括private访问权限的成员信息第四章:JNI 函数一,JNIEnv简介JNIEnv 的类型是一个指针,指向存储全部JNI 函数指针的结构。

每个函数均可通过JNIEnv 参数以固定偏移量进行访问。

二,常用的API简介JNI的API非常多,我们这里只讲解比较常用的API,如下:1,类操作通过对象来获取类jclass GetObjectClass(JNIEnv *env, jobject obj);通过签名来查找类jclass FindClass(JNIEnv *env, const char *name);2,全局及局部引用全局引用jobject NewGlobalRef(JNIEnv *env, jobject obj);void DeleteGlobalRef(JNIEnv *env, jobject globalRef);局部引用jobject NewLocalRef(JNIEnv *env, jobject obj);void DeleteLocalRef(JNIEnv *env, jobject localRef);3,对象操作jobject NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...);4,访问对象的域获取类的变量jfieldID GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig);通过fieldID获取该变量的值NativeType Get<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID);通过fieldID设置该变量的值void Set<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID, NativeType value);以下为静态类型处理jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig); NativeType GetStatic<type>Field(JNIEnv *env, jclass clazz, jfieldID fieldID);void SetStatic<type>Field(JNIEnv *env, jclass clazz, jfieldID fieldID, NativeType value);5,调用实例方法获取类的方法jmethodID GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig);通过methodID来调用方法NativeType Call<type>Method(JNIEnv *env, jobject obj, jmethodID methodID, ...); jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig);NativeType CallStatic<type>Method(JNIEnv *env, jclass clazz,jmethodID methodID, ...);通过类参数和methodID来调用方法NativeType CallNonvirtual<type>Method(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);这个一般用于子类调用父类时来用,用得比较少。

相关文档
最新文档