JNI开发笔记(一)

C/C++  互相通过的接口,本地的C/C++代码可以调用Java代码
JNI是本地编程接口,NDK快速开发C(C++)动态库,将so和Java应用一起打包成apk
将复杂的逻辑和算法通过本地代码(C/C++)

反汇编.so动态库分析程序的逻辑要复杂
设备提供C接口,而Java不能直接与C进行交互,先在Java层定义发送短信等 native方法,用javah命令将定义Java native接口的class字节码文件生成.h文件,最后用设备的C接口实现java的native方法,编译成 .dll或 .so动态库


打开一个网页,播放视频或打开窗口,C++实现麻烦,用Android应用层提供的API变得容易。Cocos2d-x封装
应用程序需要调用硬件的特定功能,只能通过C/C++封装的JNI接口来提供上层应用
厂商封装好JNI接口,了解JNI与Java通讯原理

C和C++ 复用以前用C/C++写的大量代码

JNI程序受系统环境影响,C/C++编译的模块或代码依赖系统提供的库函数和本地库,不同的操作系统,有自己的本地库和CPU指令集,各个平台的C/C++规范和标准库函数实现方式也有所区别

1.编写声明native方法的Java类
2.Java源代码编程成class字节码文件
3.用javah -jni 生成 .h头文件  -jni表示将class中用native声明的函数
4.用本地代码实现 .h 文件中的函数
5.本地代码编译成动态库 Windows:*.dll Linux:*.so Mac OSx:*.jnilib
6.拷贝动态库至 java.library.path 本地库搜索目录下,运行Java程序

HelloWorld.java

public class HelloWord{
	public calss HelloWorld{
		public static native String sayHello(String name);
		
		public static void main(String[] args){
			String tet = sayHello("yang");
			System.out.println(text);
		}
	}
	
	staic{
		System.loadLibrary("HelloWorld");
	}
}

用本地代码实现 .h 文件中的函数
将C/C++代码编译成本地动态库文件,libHelloWorld.so

一般在类的静态代码块中加载动态库最合适
方式1:只需要动态库名字,不需要lib前缀,也不要.so, .dll, .jnilib后缀
System.loadLibrary("HelloWorld");  java会去java.library.path系统指定目录
方式2:指定动态库的绝对路径,需要前缀后缀
System.load("/User/yangxin/Desktop/libHelloWorld.jnilib");

javah -classpath ./bin//classpath 类搜索路径

javac src/com/HelloWorld.java -d ./bin
-d 表示编译后的class文件放在指定目录下,放在src同级的bin目录

没有将动态库拷贝到本地搜索目录下,执行 java 命令,添加系统属性 java.library.path指定动态库目录  java -Djava.library.path=/Users/yangxin/Desktop
指定系统属性,Linux环境下可设置 LD_LIBRARY_PATH 环境变量指定库的搜索目录

gcc -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -fPIC -shared
-I      包含编译JNI必要的头文件
-fPIC   编译成位置无关独立代码
-shared 编译成到动态库
-o      编译后动态库生成的路径和文件名

JNIEXPORT jstring JNICALL Java_com_study_jnilearn_HelloWorld_sayHello
(JNIEnv *, jclass, jstring)
{
	const char *c_str = NULL;
	char buff[128] = {0};
	c_str = (*env)->GetStringUTFChars(env, j_str, NULL);
	if(c_str == NULL){
		printf();
		return NULL;
	}
	(*env)->ReleaseStringUTFChars(env, j_str, c_str);
	printf("Java Str:%s\n", c_str);
	sprintf(buff, "hello %s", c_str);
	return (*env)->NewStringUTF(env, buff);
}
JVM查找native方法
   调用System.loadLibrary接口 加载实现了native方法的动态库才能正常访问
JVM查找native方法
  按照JNI规范的命名法则
  调用JNI提供的 RegisterNatives 函数,注册到JVM


编译动态库时,用-I包含了两个头文件目录,一个jni.h头文件,一个跨平台头文件目录,用于定义与平台相关的宏,其中用于标识 JNIEXPORT JNICALL
在Windows中编译dll动态库规定,如果动态库中函数要被外部调用,在函数声明中添加 __declspec(dllexport)标识,在Linux/Unix这两个宏可以省略。由于各自的编译器所产生的可执行文件格式不一样。


javah工具生成函数原型的头文件命名规则: Java_类全路径_方法名
JNIEXPORT jstring JNICALL Java_com_study_jnilearn_HelloWorld_sayHello(JNIEnv *, jclass, jstring);
第一个参数:JNIEnv * 定义任意native函数的第一个参数(调用JNI的RegisterNatives函数注册的函数),指向JVM函数表的指针,函数表每一个入口指向一个JNI函数
第二个参数:Java中调用 native 方法的实例或Class对象,如果这个native方法是实例方法,则参数是 jobject,如果是静态方法,则是 jclass
第三个参数:Java对应JNI中的数据类型,Java中String类型对应JNI中的jstring


熟悉命名规则后,不通过javah生成相应的java native方法的函数原型,只需要按照命名规则编写相应的函数原型和实现。
com.study.jni.Utils   计算加法native的add
public native int add(int, int);
JNIEXPORT jint JNICALL Java_com_study_jni_Utils_add(JNIEnv *, jobject, jint,jint);
Java层函数名如果有一个"_",转换成JNI后变成了"_l"
JNIEXPORT void JNICALL Java_android_media_MediaScanner_native_linit
JNIEXPORT void JNICALL Java_android_media_MedaiScanner_processFile


内容概要:文章基于4A架构(业务架构、应用架构、数据架构、技术架构),对SAP的成本中心和利润中心进行了详细对比分析。业务架构上,成本中心是成本控制的责任单元,负责成本归集与控制,而利润中心是利润创造的独立实体,负责收入、成本和利润的核算。应用架构方面,两者都依托于SAP的CO模块,但功能有所区分,如成本中心侧重于成本要素归集和预算管理,利润中心则关注内部交易核算和获利能力分析。数据架构中,成本中心与利润中心存在多对的关系,交易数据通过成本归集、分摊和利润计算流程联动。技术架构依赖SAP S/4HANA的内存计算和ABAP技术,支持实时核算与跨系统集成。总结来看,成本中心和利润中心在4A架构下相互关联,共同为企业提供精细化管理和决策支持。 适合人群:从事企业财务管理、成本控制或利润核算的专业人员,以及对SAP系统有定了解的企业信息化管理人员。 使用场景及目标:①帮助企业理解成本中心和利润中心在4A架构下的运作机制;②指导企业在实施SAP系统时合理配置成本中心和利润中心,优化业务流程;③提升企业对成本和利润的精细化管理水平,支持业务决策。 其他说明:文章不仅阐述了理论概念,还提供了具体的应用场景和技术实现方式,有助于读者全面理解并应用于实际工作中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值