本地方法怎么映射Java层的Java原始数据类型型

怎么使用JAVA连接数据库?_百度知道
该问题可能描述不清,建议你
怎么使用JAVA连接数据库?
答题抽奖
首次认真答题后
即可获得3次抽奖机会,100%中奖。
Java数据库连接(JDBC)由一组用 Java 编程语言编写的类和接口组成。JDBC 为工具/数据库开发人员提供了一个标准的 API,使他们能够用纯Java API 来编写数据库应用程序。然而各个开发商的接口并不完全相同,所以开发环境的变化会带来一定的配置变化。本文主要集合了不同数据库的连接方式。一、连接各种数据库方式速查表  下面罗列了各种数据库使用JDBC连接的方式,可以作为一个手册使用。   1、Oracle8/8i/9i数据库(thin模式) Class.forName(&oracle.jdbc.driver.OracleDriver&).newInstance(); String url=&jdbc:oracle:thin:@localhost:1521:orcl&; //orcl为数据库的SID String user=&test&; String password=&test&; Connection conn= DriverManager.getConnection(url,user,password);   2、DB2数据库 Class.forName(&com.ibm.db2.jdbc.app.DB2Driver &).newInstance(); String url=&jdbc:db2://localhost:5000/sample&; //sample为你的数据库名 String user=&admin&; String password=&&; Connection conn= DriverManager.getConnection(url,user,password);   3、Sql Server7.0/2000数据库 Class.forName(&com.microsoft.jdbc.sqlserver.SQLServerDriver&).newInstance(); String url=&jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=mydb&; //mydb为数据库 String user=&sa&; String password=&&; Connection conn= DriverManager.getConnection(url,user,password);   4、Sybase数据库 Class.forName(&com.sybase.jdbc.SybDriver&).newInstance(); String url =& jdbc:sybase:Tds:localhost:5007/myDB&;//myDB为你的数据库名 Properties sysProps = System.getProperties(); SysProps.put(&user&,&userid&); SysProps.put(&password&,&user_password&); Connection conn= DriverManager.getConnection(url, SysProps);   5、Informix数据库 Class.forName(&com.informix.jdbc.IfxDriver&).newInstance(); String url = &jdbc:informix-sqli://123.45.67.89:1533/myDB:INFORMIXSERVER= user=password=testpassword&; //myDB为数据库名 Connection conn= DriverManager.getConnection(url);   6、MySQL数据库 Class.forName(&org.gjt.mm.mysql.Driver&).newInstance(); String url =&jdbc:mysql://localhost/myDB?user=soft&password=soft1234&useUnicode=true&characterEncoding=8859_1& //myDB为数据库名 Connection conn= DriverManager.getConnection(url);   7、PostgreSQL数据库 Class.forName(&org.postgresql.Driver&).newInstance(); String url =&jdbc:postgresql://localhost/myDB& //myDB为数据库名 String user=&myuser&; String password=&mypassword&; Connection conn= DriverManager.getConnection(url,user,password);   8、access数据库直连用ODBC的Class.forName(&sun.jdbc.odbc.JdbcOdbcDriver&) ;String url=&jdbc:odbc:Driver={MicroSoft Access Driver (*.mdb)};DBQ=&+application.getRealPath(&/Data/ReportDemo.mdb&);Connection conn = DriverManager.getConnection(url,&&,&&);Statement stmtNew=conn.createStatement() ;二、JDBC连接MySql方式  下面是使用JDBC连接MySql的一个小的教程   1、查找驱动程序  MySQL目前提供的java驱动程序为Connection/J,可以从MySQL官方网站下载,并找到mysql-connector-java-3.0.15-ga-bin.jar文件,此驱动程序为纯java驱动程序,不需做其他配置。  2、动态指定classpath  如果需要执行时动态指定classpath,就在执行时采用-cp方式。否则将上面的.jar文件加入到classpath环境变量中。  3、加载驱动程序try{ Class.forName(com.mysql.jdbc.Driver); System.out.println(Success loading Mysql Driver!);}catch(Exception e){ System.out.println(Error loading Mysql Driver!); e.printStackTrace();}  4、设置连接的urljdbc:mysql://localhost/databasename[?pa=va][&pa=va]  三、以下列出了在使用JDBC来连接Oracle数据库时可以使用的一些技巧  1、在客户端软件开发中使用Thin驱动程序  在开发Java软件方面,Oracle的数据库提供了四种类型的驱动程序,二种用于应用软件、applets、servlets等客户端软件,另外二种用于数据库中的Java存储过程等服务器端软件。在客户机端软件的开发中,我们可以选择OCI驱动程序或Thin驱动程序。OCI驱动程序利用Java本地化接口(JNI),通过Oracle客户端软件与数据库进行通讯。Thin驱动程序是纯Java驱动程序,它直接与数据库进行通讯。为了获得最高的性能,Oracle建议在客户端软件的开发中使用OCI驱动程序,这似乎是正确的。但我建议使用Thin驱动程序,因为通过多次测试发现,在通常情况下,Thin驱动程序的性能都超过了OCI驱动程序。  2、关闭自动提交功能,提高系统性能  在第一次建立与数据库的连接时,在缺省情况下,连接是在自动提交模式下的。为了获得更好的性能,可以通过调用带布尔值false参数的Connection类的setAutoCommit()方法关闭自动提交功能,如下所示:  conn.setAutoCommit(false);  值得注意的是,一旦关闭了自动提交功能,我们就需要通过调用Connection类的commit()和rollback()方法来人工的方式对事务进行管理。  3、在动态SQL或有时间限制的命令中使用Statement对象  在执行SQL命令时,我们有二种选择:可以使用PreparedStatement对象,也可以使用Statement对象。无论多少次地使用同一个SQL命令,PreparedStatement都只对它解析和编译一次。当使用Statement对象时,每次执行一个SQL命令时,都会对它进行解析和编译。这可能会使你认为,使用PreparedStatement对象比使用Statement对象的速度更快。然而,我进行的测试表明,在客户端软件中,情况并非如此。因此,在有时间限制的SQL操作中,除非成批地处理SQL命令,我们应当考虑使用Statement对象。  此外,使用Statement对象也使得编写动态SQL命令更加简单,因为我们可以将字符串连接在一起,建立一个有效的SQL命令。因此,我认为,Statement对象可以使动态SQL命令的创建和执行变得更加简单。  4、利用helper函数对动态SQL命令进行格式化  在创建使用Statement对象执行的动态SQL命令时,我们需要处理一些格式化方面的问题。例如,如果我们想创建一个将名字O'Reilly插入表中的SQL命令,则必须使用二个相连的“''”号替换O'Reilly中的“'”号。完成这些工作的最好的方法是创建一个完成替换操作的helper方法,然后在连接字符串心服用公式表达一个SQL命令时,使用创建的helper方法。与此类似的是,我们可以让helper方法接受一个Date型的值,然后让它输出基于Oracle的to_date()函数的字符串表达式。  5、利用PreparedStatement对象提高数据库的总体效率  在使用PreparedStatement对象执行SQL命令时,命令被数据库进行解析和编译,然后被放到命令缓冲区。然后,每当执行同一个PreparedStatement对象时,它就会被再解析一次,但不会被再次编译。在缓冲区中可以发现预编译的命令,并且可以重新使用。在有大量用户的企业级应用软件中,经常会重复执行相同的SQL命令,使用PreparedStatement对象带来的编译次数的减少能够提高数据库的总体性能。如果不是在客户端创建、预备、执行PreparedStatement任务需要的时间长于Statement任务,我会建议在除动态SQL命令之外的所有情况下使用PreparedStatement对象。  6、在成批处理重复的插入或更新操作中使用PreparedStatement对象  如果成批地处理插入和更新操作,就能够显著地减少它们所需要的时间。Oracle提供的Statement和 CallableStatement并不真正地支持批处理,只有PreparedStatement对象才真正地支持批处理。我们可以使用addBatch()和executeBatch()方法选择标准的JDBC批处理,或者通过利用PreparedStatement对象的setExecuteBatch()方法和标准的executeUpdate()方法选择速度更快的Oracle专有的方法。要使用Oracle专有的批处理机制,可以以如下所示的方式调用setExecuteBatch():PreparedStatement pstmt3Dtry { ((OraclePreparedStatement)pstmt).setExecuteBatch(30); ... pstmt.executeUpdate();}   调用setExecuteBatch()时指定的值是一个上限,当达到该值时,就会自动地引发SQL命令执行,标准的executeUpdate()方法就会被作为批处理送到数据库中。我们可以通过调用PreparedStatement类的sendBatch()方法随时传输批处理任务。  7、使用Oracle locator方法插入、更新大对象(LOB)  Oracle的PreparedStatement类不完全支持BLOB和CLOB等大对象的处理,尤其是Thin驱动程序不支持利用PreparedStatement对象的setObject()和setBinaryStream()方法设置BLOB的值,也不支持利用setCharacterStream()方法设置CLOB的值。只有locator本身中的方法才能够从数据库中获取LOB类型的值。可以使用PreparedStatement对象插入或更新LOB,但需要使用locator才能获取LOB的值。由于存在这二个问题,因此,我建议使用locator的方法来插入、更新或获取LOB的值。  8、使用SQL92语法调用存储过程  在调用存储过程时,我们可以使用SQL92或Oracle PL/SQL,由于使用Oracle PL/SQL并没有什么实际的好处,而且会给以后维护你的应用程序的开发人员带来麻烦,因此,我建议在调用存储过程时使用SQL92。  9、使用Object SQL将对象模式转移到数据库中  既然可以将Oracle的数据库作为一种面向对象的数据库来使用,就可以考虑将应用程序中的面向对象模式转到数据库中。目前的方法是创建Java bean作为伪装的数据库对象,将它们的属性映射到关系表中,然后在这些bean中添加方法。尽管这样作在Java中没有什么问题,但由于操作都是在数据库之外进行的,因此其他访问数据库的应用软件无法利用对象模式。如果利用Oracle的面向对象的技术,可以通过创建一个新的数据库对象类型在数据库中模仿其数据和操作,然后使用JPublisher等工具生成自己的Java bean类。如果使用这种方式,不但Java应用程序可以使用应用软件的对象模式,其他需要共享你的应用中的数据和操作的应用软件也可以使用应用软件中的对象模式。  10、利用SQL完成数据库内的操作
----希望对你有用,具体这方面的网上很多,学习的时候多看看别人写的代码了,可以提升自己.....
采纳数:4815
获赞数:7847
当然是通过jdbc啊
你是说用JDBC连接还是用框架连接???????
为你推荐:
其他类似问题
您可能关注的内容
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。在java类里用到本地的dll(因为要跟设备打交道),路径应该怎么设置,现在的问题就是java类在tomcat服务器的环境下,调不到本地代码。我的本地dll和java类是没有问题的,因为我用eclipse在本地机上测试是没问题的。谢谢!
试试把dll所在的路径加到tomcat的启动脚本的PATH变量里面去。
能说详细点吗?谢谢!
算了,你把那个dll文件拷贝到Tomcat使用的JDK所在的&JDK_HOME&\jre\bin目录下,那么程序中的Java肯定可以调用到。
企业级软件架构解决之道
如有意见请与我们联系 Powered by JdonFramework基础数据类型 - 简书
基础数据类型
开发者使用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);
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字符的值都在1~127之间,这些值在UTF-8编码中保持原样。一个字节如果最高位被设置了,意味着这是一个多字节字符(16-bitUnicode值)。
函数Java_Prompt_getLine通过调用JNI函数GetStringUTFChars来读取字符串的内容。GetStringUTFChars可以把一个jstring指针(指向JVM内部的Unicode字符序列)转化成一个UTF-8格式的C字符串。如何你确信原始字符串数据只包含7-bit ASCII字符,你可以把转化后的字符串传递给常规的C库函数使用,如printf。我们会在8.2中讨论如何处理非ASCII字符串。
JNIEXPORT jstring JNICALL
Java_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt)
char buf[128];
const jbyte *
str = (*env)-&GetStringUTFChars(env, prompt, NULL);
if (str == NULL) {
return NULL; /* OutOfMemoryError already thrown */
printf("%s", str);
(*env)-&ReleaseStringUTFChars(env, prompt, str);
/* We assume here that the user does not type more than
* 127 characters */
scanf("%s", buf);
不要忘记检查GetStringUTFChars。因为JVM需要为新诞生的UTF-8字符串分配内存,这个操作有可能因为内存太少而失败。失败时,GetStringUTFChars会返回NULL,并抛出一个OutOfMemoryError异常(对异常的处理在第6章)。这些JNI抛出的异常与JAVA中的异常是不同的。一个由JNI抛出的未决的异常不会改变程序执行流,因此,我们需要一个显示的return语句来跳过C函数中的剩余语句。Java_Prompt_getLine函数返回后,异常会在Prompt.main(Prompt.getLine这个发生异常的函数的调用者)中抛出,
3.2.2 释放本地字符串资源
从GetStringUTFChars中获取的UTF-8字符串在本地代码中使用完毕后,要使用ReleaseStringUTFChars告诉JVM这个UTF-8字符串不会被使用了,因为这个UTF-8字符串占用的内存会被回收。
3.2.3 构造新的字符串
你可以通过JNI函数NewStringUTF在本地方法中创建一个新的java.lang.String字符串对象。这个新创建的字符串对象拥有一个与给定的UTF-8编码的C类型字符串内容相同的Unicode编码字符串。
如果一个VM不能为构造java.lang.String分配足够的内存,NewStringUTF会抛出一个OutOfMemoryError异常,并返回一个NULL。在这个例子中,我们不必检查它的返回值,因为本地方法会立即返回。如果NewStringUTF失败,OutOfMemoryError这个异常会被在Prompt.main(本地方法的调用者)中抛出。如果NeweStringUTF成功,它会返回一个JNI引用,这个引用指向新创建的java.lang.String对象。这个对象被Prompt.getLine返回然后被赋值给Prompt.main中的本地input。
3.2.4 其它JNI字符串处理函数
JNI支持许多操作字符串的函数,这里做个大致介绍。
GetStringChars和ReleaseStringChars获取以Unicode格式编码的字符串。当操作系统支持Unicode编码的字符串时,这些方法很有用。
UTF-8字符串以’\0’结尾,而Unicode字符串不是。如果jstring指向一个Unicode编码的字符串,为了得到这个字符串的长度,可以调用GetStringLength。如果一个jstring指向一个UTF-8编码的字符串,为了得到这个字符串的字节长度,可以调用标准C函数strlen。或者直接对jstring调用JNI函数GetStringUTFLength,而不用管jstring指向的字符串的编码格式。
GetStringChars和GetStringUTFChars函数中的第三个参数需要更进一步的解释:
const jchar *
GetStringChars(JNIEnv *env, jstring str, jboolean *isCopy);
当从JNI函数GetStringChars中返回得到字符串B时,如果B是原始字符串java.lang.String的拷贝,则isCopy被赋值为JNI_TRUE。如果B和原始字符串指向的是JVM中的同一份数据,则isCopy被赋值为JNI_FALSE。当isCopy值为JNI_FALSE时,本地代码决不能修改字符串的内容,否则JVM中的原始字符串也会被修改,这会打破JAVA语言中字符串不可变的规则。
通常,因为你不必关心JVM是否会返回原始字符串的拷贝,你只需要为isCopy传递NULL作为参数。
JVM是否会通过拷贝原始Unicode字符串来生成UTF-8字符串是不可以预测的,程序员最好假设它会进行拷贝,而这个操作是花费时间和内存的。一个典型的JVM会在heap上为对象分配内存。一旦一个JAVA字符串对象的指针被传递给本地代码,GC就不会再碰这个字符串。换言之,这种情况下,JVM必须pin这个对象。可是,大量地pin一个对象是会产生内存碎片的,因为,虚拟机会随意性地来选择是复制还是直接传递指针。
当你不再使用一个从GetStringChars得到的字符串时,不管JVM内部是采用复制还是直接传递指针的方式,都不要忘记调用ReleaseStringChars。根据方法GetStringChars是复制还是直接返回指针,ReleaseStringChars会释放复制对象时所占的内存,或者unpin这个对象。
3.2.5 JDK1.2中关于字符串的新JNI函数
为了提高JVM返回字符串直接指针的可能性,JDK1.2中引入了一对新函数,Get/ReleaseStringCritical。表面上,它们和Get/ReleaseStringChars函数差不多,但实际上这两个函数在使用有很大的限制。
使用这两个函数时,你必须两个函数中间的代码是运行在"critical region"(临界区)的,即,这两个函数中间的本地代码不能调用任何会让线程阻塞或等待JVM中的其它线程的本地函数或JNI函数。
有了这些限制, JVM就可以在本地方法持有一个从GetStringCritical得到的字符串的直接指针时禁止GC。当GC被禁止时,任何线程如果触发GC的话,都会被阻塞。而Get/ReleaseStringCritical这两个函数中间的任何本地代码都不可以执行会导致阻塞的调用或者为新对象在JVM中分配内存。否则,JVM有可能死锁,想象一下这样的场景中:
1、 只有当前线程触发的GC完成阻塞并释放GC时,由其它线程触发的GC才可能由阻塞中释放出来继续运行。
2、 在这个过程中,当前线程会一直阻塞。因为任何阻塞性调用都需要获取一个正被其它线程持有的锁,而其它线程正等待GC。
Get/ReleaseStringCritical的交迭调用是安全的,这种情况下,它们的使用必须有严格的顺序限制。而且,我们一定要记住检查是否因为内存溢出而导致它的返回值是NULL。因为JVM在执行GetStringCritical这个函数时,仍有发生数据复制的可能性,尤其是当JVM内部存储的数组不连续时,为了返回一个指向连续内存空间的指针,JVM必须复制所有数据。
总之,为了避免死锁,在Get/ReleaseStringCritical之间不要调用任何JNI函数。Get/ReleaseStringCritical和 Get/ReleasePrimitiveArrayCritical这两个函数是可以的。
下面代码演示了这对函数的正确用法:
jchar *s1, *s2;
s1 = (*env)-&GetStringCritical(env, jstr1);
if (s1 == NULL) {
... /* error handling */
s2 = (*env)-&GetStringCritical(env, jstr2);
if (s2 == NULL) {
(*env)-&ReleaseStringCritical(env, jstr1, s1);
... /* error handling */
/* use s1 and s2 */
(*env)-&ReleaseStringCritical(env, jstr1, s1);
(*env)-&ReleaseStringCritical(env, jstr2, s2);
JNI不支持Get/ReleaseStringUTFCritical,因为这样的函数在进行编码转换时很可能会促使JVM对数据进行复制,因为JVM内部表示字符串一般都是使用Unicode的。
JDK1.2还一对新增的函数:GetStringRegion和GetStringUTFRegion。这对函数把字符串复制到一个预先分配的缓冲区内。Prompt.getLine这个本地方法可以用GetStringUTFRegion重新实现如下:
JNIEXPORT jstring JNICALL
Java_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt)
/* assume the prompt string and user input has less than 128
characters */
char outbuf[128], inbuf[128];
int len = (*env)-&GetStringLength(env, prompt);
(*env)-&GetStringUTFRegion(env, prompt, 0, len, outbuf);
printf("%s", outbuf);
scanf("%s", inbuf);
return (*env)-&NewStringUTF(env, inbuf);
GetStringUTFRegion这个函数会做越界检查,如果必要的话,会抛出异常StringIndexOutOfBoundsException。这个方法与GetStringUTFChars比较相似,不同的是,GetStringUTFRegion不做任何内存分配,不会抛出内存溢出异常。
3.2.6 JNI字符串操作函数总结
对于小字符串来说,Get/SetStringRegion和Get/SetString-UTFRegion这两对函数是最佳选择,因为缓冲区可以被编译器提前分配,而且永远不会产生内存溢出的异常。当你需要处理一个字符串的一部分时,使用这对函数也是不错的,因为它们提供了一个开始索引和子字符串的长度值。另外,复制少量字符串的消耗是非常小的。
在使用GetStringCritical时,必须非常小心。你必须确保在持有一个由GetStringCritical获取到的指针时,本地代码不会在JVM内部分配新对象,或者做任何其它可能导致系统死锁的阻塞性调用。
下面的例子演示了使用GetStringCritical时需要注意的一些地方:
/* This is not safe! */
const char *c_str = (*env)-&GetStringCritical(env, j_str, 0);
if (c_str == NULL) {
... /* error handling */
fprintf(fd, "%s\n", c_str);
(*env)-&ReleaseStringCritical(env, j_str, c_str);
上面代码的问题在于,GC被当前线程禁止的情况下,向一个文件写数据不一定安全。例如,另外一个线程T正在等待从文件fd中读取数据。假设操作系统的规则是fprintf会等待线程T完成所有对文件fd的数据读取操作,这种情况下就可能会产生死锁:线程T从文件fd中读取数据是需要缓冲区的,如果当前没有足够内存,线程T就会请求GC来回收一部分,GC一旦运行,就只能等到当前线程运行ReleaseStringCritical时才可以。而ReleaseStringCritical只有在fprintf调用返回时才会被调用。而fprintf这个调用,会一直等待线程T完成文件读取操作。
3.3 访问数组
JNI在处理基本类型数组和对象数组上面是不同的。对象数组里面是一些指向对象实例或者其它数组的引用。
本地代码中访问JVM中的数组和访问JVM中的字符串有些相似。看一个简单的例子。下面的程序调用了一个本地方法sumArray,这个方法对一个int数组里面的元素进行累加:
class IntArray {
private native int sumArray(int[] arr);
public static void main(String[] args) {
IntArray p = new IntArray();
int arr[] = new int[10];
for (int i = 0; i & 10; i++) {
int sum = p.sumArray(arr);
System.out.println("sum = " + sum);
System.loadLibrary("IntArray");
3.3.1 在本地代码中访问数组
数组的引用类型是一般是jarray或者或者jarray的子类型jintArray。就像jstring不是一个C字符串类型一样,jarray也不是一个C数组类型。所以,不要直接访问jarray。你必须使用合适的JNI函数来访问基本数组元素:
JNIEXPORT jint JNICALL
Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr)
jint buf[10];
jint i, sum = 0;
(*env)-&GetIntArrayRegion(env, arr, 0, 10, buf);
for (i = 0; i & 10; i++) {
sum += buf[i];
3.3.2 访问基本类型数组
上一个例子中,使用GetIntArrayRegion函数来把一个int数组中的所有元素复制到一个C缓冲区中,然后我们在本地代码中通过C缓冲区来访问这些元素。
JNI支持一个与GetIntArrayRegion相对应的函数SetIntArrayRegion。这个函数允许本地代码修改所有的基本类型数组中的元素。
JNI支持一系列的Get/Release&Type&ArrayElement函数,这些函数允许本地代码获取一个指向基本类型数组的元素的指针。由于GC可能不支持pin操作,JVM可能会先对原始数据进行复制,然后返回指向这个缓冲区的指针。我们可以重写上面的本地方法实现:
JNIEXPORT jint JNICALL
Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr)
jint i, sum = 0;
carr = (*env)-&GetIntArrayElements(env, arr, NULL);
if (carr == NULL) {
return 0; /* exception occurred */
for (i=0; i&10; i++) {
sum += carr[i];
(*env)-&ReleaseIntArrayElements(env, arr, carr, 0);
GetArrayLength这个函数返回数组中元素的个数,这个值在数组被首次分配时确定下来。
JDK1.2引入了一对函数:Get/ReleasePrimitiveArrayCritical。通过这对函数,可以在本地代码访问基本类型数组元素的时候禁止GC的运行。但程序员使用这对函数时,必须和使用Get/ReleaseStringCritical时一样的小心。在这对函数调用的中间,同样不能调用任何JNI函数,或者做其它可能会导致程序死锁的阻塞性操作。
3.3.3 操作基本类型数组的JNI函数的总结
如果你想在一个预先分配的C缓冲区和内存之间交换数据,应该使用Get/Set&/Type&ArrayRegion系列函数。这些函数会进行越界检查,在需要的时候会有可能抛出ArrayIndexOutOfBoundsException异常。
对于少量的、固定大小的数组,Get/Set&Type&ArrayRegion是最好的选择,因为C缓冲区可以在Stack(栈)上被很快地分配,而且复制少量数组元素的代价是很小的。这对函数的另外一个优点就是,允许你通过传入一个索引和长度来实现对子字符串的操作。
如果你没有一个预先分配的C缓冲区,并且原始数组长度未定,而本地代码又不想在获取数组元素的指针时阻塞的话,使用Get/ReleasePrimitiveArrayCritical函数对。就像Get/ReleaseStringCritical函数对一样,这对函数很小心地使用,以避免死锁。
Get/Release&type&ArrayElements系列函数永远是安全的。JVM会选择性地返回一个指针,这个指针可能指向原始数据也可能指向原始数据复制。
3.3.5 访问对象数组
JNI提供了一个函数对来访问对象数组。GetObjectArrayElement返回数组中指定位置的元素,而SetObjectArrayElement修改数组中指定位置的元素。与基本类型的数组不同的是,你不能一次得到所有的对象元素或者一次复制多个对象元素。字符串和数组都是引用类型,你要使用Get/SetObjectArrayElement来访问字符串数组或者数组的数组。
下面的例子调用了一个本地方法来创建一个二维的int数组,然后打印这个数组的内容:
class ObjectArrayTest {
private static native int[][] initInt2DArray(int size);
public static void main(String[] args) {
int[][] i2arr = initInt2DArray(3);
for (int i = 0; i & 3; i++) {
for (int j = 0; j & 3; j++) {
System.out.print(" " + i2arr[i][j]);
System.out.println();
System.loadLibrary("ObjectArrayTest");
静态本地方法initInt2DArray创建了一个给定大小的二维数组。执行分配和初始化数组任务的本地方法可以是下面这样子的:
JNIEXPORT jobjectArray JNICALL
Java_ObjectArrayTest_initInt2DArray(JNIEnv *env,
jclass cls,
jclass intArrCls = (*env)-&FindClass(env, "[I");
if (intArrCls == NULL) {
return NULL; /* exception thrown */
result = (*env)-&NewObjectArray(env, size, intArrCls,
if (result == NULL) {
return NULL; /* out of memory error thrown */
for (i = 0; i & i++) {
jint tmp[256];
/* make sure it is large enough! */
jintArray iarr = (*env)-&NewIntArray(env, size);
if (iarr == NULL) {
return NULL; /* out of memory error thrown */
for (j = 0; j & j++) {
tmp[j] = i +
(*env)-&SetIntArrayRegion(env, iarr, 0, size, tmp);
(*env)-&SetObjectArrayElement(env, result, i, iarr);
(*env)-&DeleteLocalRef(env, iarr);
函数newInt2DArray首先调用JNI函数FindClass来获得一个int型二维数组类的引用,传递给FindClass的参数“[I”是JNI class descriptor(JNI类型描述符),它对应着JVM中的int[]类型。如果类加载失败的话,FindClass会返回NULL,然后抛出一个异常。
接下来,NewObjectArray会分配一个数组,这个数组里面的元素类型用intArrCls类引用来标识。函数NewObjectArray只能分配第一维,JVM没有与多维数组相对应的数据结构。一个二维数组实际上就是一个简单的数组的数组。
创建第二维数据的方式非常直接,NewInt-Array为每个数组元素分配空间,然后SetIntArrayRegion把tmp[]缓冲区中的内容复制到新分配的一维数组中去。
在循环最后调用DeleteLocalRef,确保JVM释放掉iarr这个JNI引用。
要素 :1、 该函数大全是基于C语言方式的,对于C++方式可以直接转换 ,例如,对于生成一个jstring类型的方法转换分别如下: C编程环境中使用方法为:(*env)-&NewStringUTF(env , &123&) ; C++编程环境中(例如,VC下)则是:env-...
*** 说明:本文不代表博主观点,均是由以下资料整理的读书笔记。 *** 【参考资料】 1、向您的Android Studio项目添加C/C++代码2、Google开发者文档 -- 添加C++代码到现有Android Studio项目中3、JNI Tips 英文原版4、JN...
Kotlin学习之基础数据类型 @(Kotlin学习) Kotlin的基础数据类型包括数字类型、字符类型、字符串类型和布尔类型。 一、数字类型 除char类型外,Java中的基本数据类型在Kotlin中都有相应的数据类型,而且长度都是相同的: 因为Kotlin中不存在基本数...
package jibenshujuleixing/*Kotlin 基本数值类型包括 Byte8 Short16 Int32 Long64 Float32 Double64不同于java的是字符不属于数值类型,是一个独立的数据类型 */ //---------------比...
注:原文地址 1. JNI 概念 1.1 概念 JNI 全称 Java Native Interface,Java 本地化接口,可以通过 JNI 调用系统提供的 API。操作系统,无论是 Linux,Windows 还是 Mac OS,或者一些汇编语言写的底层硬件驱动都是 ...
web前端性能优化总结 浏览器访问优化 1、减少http请求,合理设置 HTTP缓存2、使用浏览器缓存3、启用压缩4、CSS Sprites5、LazyLoad Images6、CSS放在页面最上部,javascript放在页面最下面7、异步请求Callback(就是将一些...
出去读大学后,愈发地想家,随着假期的临近,在电话里也能感受到爸妈心情的变化。他们很想我,我也很想他们。
回来后,自是心肝宝贝,而我,似乎也享受着这种爱意。
只是啊,好景不会长吧,慢慢的,我会变得做什么事都会被骂,出门被骂,不出门也被骂,早起被骂,晚起也被骂...
家乡 美与丑 善与恶 逃离与思念的熔铸体 时代太快 父辈与子女的连接管道已被世界撕裂 时代 是最大的鸿沟 越是相互了解的邻里 充满人情的甜腻 冲刷出是的嫉妒攀比催生的阴沟
太小的天空无法满足联通全球的视野 游子回头 只能望见故土上空厚重的 阴霾 朦胧的旧居 肮脏拥挤的角落...
从2015年8月到2016年的4月,已经在绿盟科技工作了8个月了。 有心酸,也有快乐。从懵懂的技术小白,到现在也还是有点懵懂的刚入门的小菜鸟,经历了两个技术经理。一个严厉,一个宽松。 现在的状态是,想专心做服务项目,但是由于办事处分为了售前和售后的关系,售前只做售前交流和文...
前段时间母亲给我打电话,说她找人给我算命。母亲认真的跟我说算命先生说我以后会有多好,会有一个和谐的家庭,会有一份舒适的工作。我笑着附和,不想否定什么,我知道母亲对我倾注了所有的心血,他希望我的未来是美好,并且一帆风顺的。
挂完电话,我开始认真的思考,我需要怎样的未...}

我要回帖

更多关于 java数据类型 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信