java JNI编程指南.doc_第1页
java JNI编程指南.doc_第2页
java JNI编程指南.doc_第3页
java JNI编程指南.doc_第4页
java JNI编程指南.doc_第5页
已阅读5页,还剩83页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

题目有点大,呵呵。前边是高老师的东东,后边是我的小实践。话说当时Android还是1.5的。Android JNI知识简介Java Native Interface (JNI)标准是java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI 是本地编程接口,它使得在 Java 虚拟机 (VM) 内部运行的 Java 代码能够与用其它编程语言(如 C、C+ 和汇编语言)编写的应用程序和库进行交互操作。1.从如何载入.so档案谈起 由于Android的应用层的类都是以Java写的,这些Java类编译为Dex型式的Bytecode之后,必须靠Dalvik虚拟机(VM: Virtual Machine)来执行。VM在Android平台里,扮演很重要的角色。 此外,在执行Java类的过程中,如果Java类需要与C组件沟通时,VM就会去载入C组件,然后让Java的函数顺利地调用到C组件的函数。此时,VM扮演着桥梁的角色,让Java与C组件能通过标准的JNI介面而相互沟通。 应用层的Java类是在虚拟机(VM: Vitual Machine)上执行的,而C件不是在VM上执行,那么Java程式又如何要求VM去载入(Load)所指定的C组件呢? 可使用下述指令: System.loadLibrary(*.so的档案名); 例如,Android框架里所提供的MediaPlayer.java类,含指令: public class MediaPlayer static System.loadLibrary(media_jni); 这要求VM去载入Android的/system/lib/libmedia_jni.so档案。载入*.so之后,Java类与*.so档案就汇合起来,一起执行了。2.如何撰写*.so的入口函数 - JNI_OnLoad()与JNI_OnUnload()函数的用途当Android的VM(Virtual Machine)执行到System.loadLibrary()函数时,首先会去执行C组件里的JNI_OnLoad()函数。它的用途有二: (1)告诉VM此C组件使用那一个JNI版本。如果你的*.so档没有提供JNI_OnLoad()函数,VM会默认该*.so档是使用最老的JNI 1.1版本。由于新版的JNI做了许多扩充,如果需要使用JNI的新版功能,例如JNI 1.4的java.nio.ByteBuffer,就必须藉由JNI_OnLoad()函数来告知VM。(2)由于VM执行到System.loadLibrary()函数时,就会立即先呼叫JNI_OnLoad(),所以C组件的开发者可以藉由JNI_OnLoad()来进行C组件内的初期值之设定(Initialization) 。例如,在Android的/system/lib/libmedia_jni.so档案里,就提供了JNI_OnLoad()函数,其程式码片段为:/#define LOG_NDEBUG 0#define LOG_TAG MediaPlayer-JNIjint JNI_OnLoad(JavaVM* vm, void* reserved) JNIEnv* env = NULL; jint result = -1; if (vm-GetEnv(void*) &env, JNI_VERSION_1_4) != JNI_OK) LOGE(ERROR: GetEnv failedn); goto bail; assert(env != NULL); if (register_android_media_MediaPlayer(env) 0) LOGE(ERROR: MediaPlayer native registration failedn); goto bail; if (register_android_media_MediaRecorder(env) 0) LOGE(ERROR: MediaRecorder native registration failedn); goto bail; if (register_android_media_MediaScanner(env) 0) LOGE(ERROR: MediaScanner native registration failedn); goto bail; if (register_android_media_MediaMetadataRetriever(env) 0) LOGE(ERROR: MediaMetadataRetriever native registration failedn); goto bail; /* success - return valid version number */ result = JNI_VERSION_1_4;bail: return result;此函数回传JNI_VERSION_1_4值给VM,于是VM知道了其所使用的JNI版本了。此外,它也做了一些初期的动作(可呼叫任何本地函数),例如指令: if (register_android_media_MediaPlayer(env) GetEnv(void*) &env, JNI_VERSION_1_4) != JNI_OK) LOGE(ERROR: GetEnv failedn); goto bail; 由于VM通常是多执行绪(Multi-threading)的执行环境。每一个执行绪在呼叫JNI_OnLoad()时,所传递进来的JNIEnv指标值都是不同的。为了配合这种多执行绪的环境,C组件开发者在撰写本地函数时,可藉由JNIEnv指标值之不同而避免执行绪的资料冲突问题,才能确保所写的本地函数能安全地在Android的多执行绪VM里安全地执行。基于这个理由,当在呼叫C组件的函数时,都会将JNIEnv指标值传递给它,如下:jint JNI_OnLoad(JavaVM* vm, void* reserved)JNIEnv* env = NULL; if (register_android_media_MediaPlayer(env) MonitorEnter(env, obj) != JNI_OK) 查看是否已经有其他执行绪进入此物件,如果没有,此执行绪就进入该物件里执行了。还有,也可撰写下述指令: if (*env)-MonitorExit(env, obj) != JNI_OK) 查看是否此执行绪正在此物件内执行,如果是,此执行绪就会立即离开。3.registerNativeMethods()函数的用途应用层级的Java类别透过VM而呼叫到本地函数。一般是仰赖VM去寻找*.so里的本地函数。如果需要连续呼叫很多次,每次都需要寻找一遍,会多花许多时间。此时,组件开发者可以自行将本地函数向VM进行登记。例如,在Android的/system/lib/libmedia_jni.so档案里的代码段如下:/#define LOG_NDEBUG 0#define LOG_TAG MediaPlayer-JNIstatic JNINativeMethod gMethods = setDataSource, (Ljava/lang/String;)V, (void *)android_media_MediaPlayer_setDataSource, setDataSource, (Ljava/io/FileDescriptor;JJ)V, (void *)android_media_MediaPlayer_setDataSourceFD, prepare, ()V, (void *)android_media_MediaPlayer_prepare, prepareAsync, ()V, (void *)android_media_MediaPlayer_prepareAsync, _start, ()V, (void *)android_media_MediaPlayer_start, _stop, ()V, (void *)android_media_MediaPlayer_stop, getVideoWidth, ()I, (void *)android_media_MediaPlayer_getVideoWidth, getVideoHeight, ()I, (void *)android_media_MediaPlayer_getVideoHeight, seekTo, (I)V, (void *)android_media_MediaPlayer_seekTo, _pause, ()V, (void *)android_media_MediaPlayer_pause, isPlaying, ()Z, (void *)android_media_MediaPlayer_isPlaying, getCurrentPosition, ()I, (void *)android_media_MediaPlayer_getCurrentPosition, getDuration, ()I, (void *)android_media_MediaPlayer_getDuration, _release, ()V, (void *)android_media_MediaPlayer_release, _reset, ()V, (void *)android_media_MediaPlayer_reset, setAudioStreamType,(I)V, (void *)android_media_MediaPlayer_setAudioStreamType, setLooping, (Z)V, (void *)android_media_MediaPlayer_setLooping, setVolume, (FF)V, (void *)android_media_MediaPlayer_setVolume, getFrameAt, (I)Landroid/graphics/Bitmap;, (void *)android_media_MediaPlayer_getFrameAt, native_setup, (Ljava/lang/Object;)V, (void *)android_media_MediaPlayer_native_setup, native_finalize, ()V, (void *)android_media_MediaPlayer_native_finalize,;static int register_android_media_MediaPlayer(JNIEnv *env) return AndroidRuntime:registerNativeMethods(env, android/media/MediaPlayer, gMethods, NELEM(gMethods);jint JNI_OnLoad(JavaVM* vm, void* reserved) if (register_android_media_MediaPlayer(env) 0) LOGE(ERROR: MediaPlayer native registration failedn); goto bail; 当VM载入libmedia_jni.so档案时,就呼叫JNI_OnLoad()函数。接着,JNI_OnLoad()呼叫register_android_media_MediaPlayer()函数。此时,就呼叫到AndroidRuntime:registerNativeMethods()函数,向VM(即AndroidRuntime)登记gMethods表格所含的本地函数了。简而言之,registerNativeMethods()函数的用途有二:(1)更有效率去找到函数。(2)可在执行期间进行抽换。由于gMethods是一个对照表,在程序执行时,可多次呼叫registerNativeMethods()函数来更换本地函数之指针,而达到弹性抽换本地函数之目的。4.Andoird 中使用了一种不同传统Java JNI的方式来定义其native的函数。其中很重要的区别是Andorid使用了一种Java 和 C 函数的映射表数组,并在其中描述了函数的参数和返回值。这个数组的类型是JNINativeMethod,定义如下:typedef struct const char* name; /*Java中函数的名字*/ const char* signature; /*描述了函数的参数和返回值*/void* fnPtr; /*函数指针,指向C函数*/ JNINativeMethod;其中比较难以理解的是第二个参数,例如()V(II)V(Ljava/lang/String;Ljava/lang/String;)V实际上这些字符是与函数的参数类型一一对应的。() 中的字符表示参数,后面的则代表返回值。例如()V 就表示void Func();(II)V 表示 void Func(int, int);具体的每一个字符的对应关系如下字符 Java类型 C类型V void voidZ jboolean booleanI jint intJ jlong longD jdouble doubleF jfloat floatB jbyte byteC jchar charS jshort short数组则以开始,用两个字符表示I jintArray intF jfloatArray floatB jbyteArray byteC jcharArray charS jshortArray shortD jdoubleArray doubleJ jlongArray longZ jbooleanArray boolean上面的都是基本类型。如果Java函数的参数是class,则以L开头,以;结尾,中间是用/ 隔开的包及类名。而其对应的C函数名的参数则为jobject. 一个例外是String类,其对应的类为jstringLjava/lang/String; String jstringLjava/net/Socket; Socket jobject如果JAVA函数位于一个嵌入类,则用$作为类名间的分隔符。例如 (Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)ZAndroid JNI编程实践一、直接使用java本身jni接口(windows/ubuntu)1.在Eclipsh中新建一个android应用程序。两个类:一个继承于Activity,UI显示用。另一个包含native方法。编译生成所有类。jnitest.java文件:package com.hello.jnitest;import android.app.Activity;import android.os.Bundle;public class jnitest extends Activity /* Called when the activity is first created. */ Override public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(R.layout.main); Nadd cal = new Nadd(); setTitle(The Native Add Result is + String.valueOf(cal.nadd(10, 19); Nadd.java文件:package com.hello.jnitest;public class Nadd static System.loadLibrary(Nadd); public native int nadd(int a, int b);以上在windows中完成。2.使用javah命令生成C/C+的.h文件。注意类要包含包名,路径文件夹下要包含所有包中的类,否则会报找不到类的错误。classpath参数指定到包名前一级文件夹,文件夹层次结构要符合java类的组织层次结构。javah -classpath ./jnitest/bin com.hello.jnitest.Naddcom_hello_jnitest_Nadd .h文件:/* DO NOT EDIT THIS FILE - it is machine generated */#include /* Header for class com_hello_jnitest_Nadd */#ifndef _Included_com_hello_jnitest_Nadd#define _Included_com_hello_jnitest_Nadd#ifdef _cplusplusextern C #endif/* Class: com_hello_jnitest_Nadd* Method: nadd* Signature: (II)I*/JNIEXPORT jint JNICALL Java_com_hello_jnitest_Nadd_nadd (JNIEnv *, jobject, jint, jint);#ifdef _cplusplus#endif#endif3.编辑.c文件实现native方法。com_hello_jnitest_Nadd.c文件:#include #include com_hello_jnitest_Nadd.hJNIEXPORT jint JNICALL Java_com_hello_jnitest_Nadd_nadd(JNIEnv * env, jobject c, jint a, jint b) return (a+b);4.编译.c文件生存动态库。arm-none-linux-gnueabi-gcc -I/home/a/work/android/jdk1.6.0_17/include -I/home/a/work/android/jdk1.6.0_17/include/linux -fpic -c com_hello_jnitest_Nadd.carm-none-linux-gnueabi-ld -T/home/a/CodeSourcery/Sourcery_G+_Lite/arm-none-linux-gnueabi/lib/ldscripts/armelf_linux_eabi.xsc -share -o libNadd.so com_hello_jnitest_Nadd.o得到libNadd.so文件。以上在ubuntu中完成。5.将相应的动态库文件push到avd的system/lib中:adb push libNadd.so /system/lib。若提示Read-only file system错误,运行adb remount命令,即可。Adb push libNadd.so /system/lib6.在eclipsh中运行原应用程序即可。以上在windows中完成。对于一中生成的so文件也可采用二中的方法编译进apk包中。只需在工程文件夹中建libsarmeabi文件夹(其他文件夹名无效,只建立libs文件夹也无效),然后将so文件拷入,编译工程即可。二.使用NDK生成本地方法(ubuntu and windows)1.安装NDK:解压,然后进入NDK解压后的目录,运行build/host-setup.sh(需要Make 3.81和awk)。若有错,修改host-setup.sh文件:将#!/bin/sh修改为#!/bin/bash,再次运行即可。2.在apps文件夹下建立自己的工程文件夹,然后在该文件夹下建一文件Application.mk和项project文件夹。Application.mk文件:APP_PROJECT_PATH := $(call my-dir)/projectAPP_MODULES := myjni3.在project文件夹下建一jni文件夹,然后新建Android.mk和myjni.c。这里不需要用javah生成相应的.h文件,但函数名要包含相应的完整的包、类名。4.编辑相应文件内容。Android.mk文件:# Copyright (C) 2009 The Android Open Source Project# Licensed under the Apache License, Version 2.0 (the License);# you may not use this file except in compliance with the License.# You may obtain a copy of the License at# /licenses/LICENSE-2.0# Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an AS IS BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.#LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := myjniLOCAL_SRC_FILES := myjni.cinclude $(BUILD_SHARED_LIBRARY)myjni.c文件:#include #include jstringJava_com_hello_NdkTest_NdkTest_stringFromJNI( JNIEnv* env, jobject thiz ) return (*env)-NewStringUTF(env, Hello from My-JNI !);myjni文件组织:aubuntu:/work/android/ndk-1.6_r1/apps$ tree myjnimyjni|- Application.mk- project |- jni | |- Android.mk | - myjni.c - libs - armeabi - libmyjni.so4 directories, 4 files5.编译:make APP=myjni.以上内容在ubuntu完成。以下内容在windows中完成。当然也可以在ubuntu中完成。6.在eclipsh中创建android application。将myjni中自动生成的libs文件夹拷贝到当前工程文件夹中,编译运行即可。NdkTest.java文件:package com.hello.NdkTest;import android.app.Activity;import android.os.Bundle;import android.widget.TextView;public class NdkTest extends Activity /* Called when the activity is first created. */ Override public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); TextView tv = new TextView(this); tv.setText( stringFromJNI() ); setContentView(tv); public native String stringFromJNI(); static System.loadLibrary(myjni); 对于二中生成的so文件也可采用一中的方法push到avd中运行。序这四种情况下你会用到本书:1、 在Java程序中复用以前写过的C/C+代码。2、 自己实现一个java虚拟机3、 学习不同语言如何进行协作,尤其是如何实现垃圾回收和多线程。4、 把一个虚拟机实现整合到用C/C+写的程序中。本书是写给开发者的。JNI在1997年第一次发布,本书总结了SUN工程师和大量开发者两年来积累的经验。本书介绍了JNI的设计思想,对这种思想的理解是使用JNI的各种特性的基础。本书有一部分是JAVA2平台上面的JNI特征的规范说明。JNI程序员可以把这部分用作一个手册。JVM开发者在实现虚拟机的时候必须遵守这些规范。JNI的部分设计思想来源于Netscape的Java Runtime Interface(JRI)。第一章 简介JNI是JAVA平台的一个重要特征,使用它我们可以重用以前用C/C+写的大量代码。本书既是一个编程指南也是一个JNI手册。本书共包括三部分:1、 第二章通过一个简单的例子介绍了JNI。它的对象是对JNI不熟悉的初学者。2、 310章对JNI的特征进行了系统的介绍。我们会举大量的例子来说明JNI的各个特征,这些特征都是JNI中重要且常用的。3、 1113章是关于JNI的技术规范。可以把这两章当作一个手册。本书尽量去满足各类读者的需要。指南面向初学者,手册面向有经验的人和自己实现JNI规范的人。大部分读者可能是用JNI来写程序的开发者。本书会假设你有JAVA,C/C+基础。本章的剩余部分介绍了JNI的背景,扮演的角色和JNI的演化。1.1 JAVA平台和系统环境(Host Environment)系统环境代指本地操作系统环境,它有自己的本地库和CPU指令集。本地程序(Native Applications)使用C/C+这样的本地语言来编写,被编译成只能在本地系统环境下运行的二进制代码,并和本地库链接在一起。本地程序和本地库一般地会依赖于一个特定的本地系统环境。比如,一个系统下编译出来的C程序不能在另一个系统中运行。1.2 JNI扮演的角色JNI的强大特性使我们在使用JAVA平台的同时,还可以重用原来的本地代码。作为虚拟机实现的一部分,JNI允许JAVA和本地代码间的双向交互。图1.1 JNI的角色JNI可以这样与本地程序进行交互:1、 你可以使用JNI来实现“本地方法”(native methods),并在JAVA程序中调用它们。2、 JNI支持一个“调用接口”(invocation interface),它允许你把一个JVM嵌入到本地程序中。本地程序可以链接一个实现了JVM的本地库,然后使用“调用接口”执行JAVA语言编写的软件模块。例如,一个用C语言写的浏览器可以在一个嵌入式JVM上面执行从网上下载下来的applets1.3 JNI的副作用请记住,一旦使用JNI,JAVA程序就丧失了JAVA平台的两个优点:1、 程序不再跨平台。要想跨平台,必须在不同的系统环境下重新编译本地语言部分。2、 程序不再是绝对安全的,本地代码的不当使用可能导致整个程序崩溃。一个通用规则是,你应该让本地方法集中在少数几个类当中。这样就降低了JAVA和C之间的耦合性。1.4 什么场合下应该使用JNI当你开始着手准备一个使用JNI的项目时,请确认是否还有替代方案。像上一节所提到的,应用程序使用JNI会带来一些副作用。下面给出几个方案,可以避免使用JNI的时候,达到与本地代码进行交互的效果:1、 JAVA程序和本地程序使用TCP/IP或者IPC进行交互。2、 当用JAVA程序连接本地数据库时,使用JDBC提供的API。3、 JAVA程序可以使用分布式对象技术,如JAVA IDL API。这些方案的共同点是,JAVA和C 处于不同的线程,或者不同的机器上。这样,当本地程序崩溃时,不会影响到JAVA程序。下面这些场合中,同一进程内JNI的使用无法避免:1、 程序当中用到了JAVA API不提供的特殊系统环境才会有的特征。而跨进程操作又不现实。2、 你可能想访问一些己有的本地库,但又不想付出跨进程调用时的代价,如效率,内存,数据传递方面。3、 JAVA程序当中的一部分代码对效率要求非常高,如算法计算,图形渲染等。总之,只有当你必须在同一进程中调用本地代码时,再使用JNI。1.5 JNI的演化JDK1.0包含了一个本地方法接口,它允许JAVA程序调用C/C+写的程序。许多第三方的程序和JAVA类库,如:java.lang,java.io,等都依赖于本地方法来访问底层系统环境的特征。不幸的是,JDK1.0中的本地方法有两个主要问题:1、 本地方法像访问C中的结构(structures)一样访问对象中的字段。尽管如此,JVM规范并没有定义对象怎么样在内存中实现。如果一个给定的JVM实现在布局对象时,和本地方法假设的不一样,那你就不得不重新编写本地方法库。2、 因为本地方法可以保持对JVM中对象的直接指针,所以,JDK1.0中的本地方法采用了一种保守的GC策略。JNI的诞生就是为了解决这两个问题,它可以被所有平台下的JVM支持:1、 每一个VM实现方案可以支持大量的本地代码。2、 开发工具作者不必处理不同的本地方法接口。3、 最重要的是,本地代码可以运行在不同的JVM上面。JDK1.1中第一次支持JNI,但是,JDK1.1仍在使用老风格的本地代码来实现JAVA的API。这种情况在JDK1.2下被彻底改变成符合标准的写法。1.6 例子程序本书包含了大量的代码示例,还教我们如何使用javah来构建JNI程序。第二章 开始。本章通过一个简单的例子来示例如何使用JNI。我们写一个JAVA程序,并用它调用一个C函数来打印“Hello World!”。21 概述图2.1演示了如何使用JAVA程序调用C函数来打印“Hello World!”。这个过程包含下面几步:1、 创建一个类(HelloWorld.java)声明本地方法。2、 使用javac编译源文件HollowWorld.java,产生HelloWorld.class。使用javah jni来生成C头文件(HelloWorld.h),这个头文件里面包含了本地方法的函数原型。3、 用C代码写函数原型的实现。4、 把C函数实现编译成一个本地库,创建Hello-World.dll或者libHello-World.so。5、 使用java命令运行HelloWorld程序,类文件HelloWorld.class和本地库(HelloWorld.dll或者libHelloWorld.so)在运行时被加载。图2.1 编写并运行“HelloWorld”程序本章剩余部分会详细解释这几步。第三章 基本类型、字符串、数组开发者使用JNI时最常问到的是JAVA和C/C+之间如何传递数据,以及数据类型之间如何互相映射。本章我们从整数等基本类型和数组、字符串等普通的对象类型开始讲述。至于如何传递任意对象,我们将在下一章中进行讲述。3.1 一个简单的本地方法JAVA端源代码如下:class Prompt / native method that prints a prompt and reads a line private native String getLine(String prompt); public static void main(String args) Prompt p = new Prompt(); String input = p.getLine(Type a line: ); System.out.println(User typed: + input); static System.loadLibrary(Prompt); 3.1.1 本地方法的C函数原型Prompt.getLine方法可以用下面这个C函数来实现:JNIEXPORT jstring JNICALL Java_Prompt_getLine(JNIEnv *env, jobject this, jstring prompt);其中,JNIEXPORT和JNICALL这两个宏(被定义在jni.h)确保这个函数在本地库外可见,并且C编译器会进行正确的调用转换。C函数的名字构成有些讲究,在11.3中会有一个详细的解释。3.1.2 本地方法参数第一个参数JNIEnv接口指针,指向一个个函数表,函数表中的每一个入口指向一个JNI函数。本地方法经常通过这些函数来访问JVM中的数据结构。图3.1演示了JNIEnv这个指针:图3.1 JNIEnv接口指针第二个参数根据本地方法是一个静态方法还是实例方法而有所不同。本地方法是一个静态方法时,第二个参数代表本地方法所在的类;本地方法是一个实例方法时,第二个参数代表本地方法所在的对象。我们的例子当中,Java_Prompt_getLine是一个实例方法,因此jobject参数指向方法所在的对象。3.1.3 类型映射本地方法声明中的参数类型在本地语言中都有对应的类型。JNI定义了一个C/C+类型的集合,集合中每一个类型对应于JAVA中的每一个类型。JAVA中有两种类型:基本数据类型(int,float,char等)和引用类型(类,对象,数组等)。JNI对基本类型和引用类型的处理是不同的。基本类型的映射是一对一的。例如JAVA中的int类型直接对应C/C+中的jint(定义在jni.h中的一个有符号 32位整数)。12.1.1包含了JNI中所有基本类型的定义。JNI把JAVA中的对象当作一个C指针传递到本地方法中,这个指针指向JVM中的内部数据结构,而内部数据结构在内存中的存储方式是不可见的。本地代码必须通过在JNIEnv中选择适当的JNI函数来操作JVM中的对象。例如,对于java.lang.String对应的JNI类型是jstring,但本地代码只能通过GetStringUTFChars这样的JNI函数来访问字符串的内容。所有的JNI引用都是jobject类型,对了使用方便和类型安全,JNI定义了一个引用类型集合,集合当中的所有类型都是jobject的子类型。这些子类型和JAVA中常用的引用类型相对应。例如,jstring表示字符串,jobjectArray表示对象数组。3.2 访问字符串Java_Prompt_getLine接收一个jstring类型的参数prompt,jstring类型指向JVM内部的一个字符串,和常规的C字符串类型char*不同。你不能把jstring当作一个普通的C字符串。3.2.1 转换为本地字符串本地代码中,必须使用合适的JNI函数把jstring转化为C/C+字符串。JNI支持字符串在Unicode和UTF-8两种编码之间转换。Unicode字符串代表了16-bit的字符集合。UTF-8字符串使用一种向上兼容7-bit ASCII字符串的编码协议。UTF-8字符串很像NULL结尾的C字符串,在包含非ASCII字符的时候依然如此。所有的7-bitASCII字符的值都在1127之间,这些值在UTF-8编码中保持原样。一个字节如果最高位被设置了,意味着这是一个多字节字符(16-bitUnicode值)。函数Java_Prompt_getLine通过调用JNI函数GetStringUTFChars来读取字符串的内容。GetStringUTFChars可以把一个jstring指针(指向JVM内部的Unicode字符序列)转化成一

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论