java 如何调用一个已经存在的静态库,并输入和获取参数! 例如:静态库中已经存在函数 ret=ys_tpcall(aa);

java 如何调用一个已经存在的静态库,并输入和获取参数! 例如:静态库中已经存在函数 ret=ys_tpcall(aa);,第1张

给出一个windows下dll的实例。linux下a的静态库只是头文件和编译有所不同,另外需要将编译后的动态库文件放入/usr/lib下,使用ldconfig载入。

一 先制作一个系统中有的DLL文件(cpp给出的sdk接口)

既然是测试我们就把我们这个dll叫做testDll吧,为了简单其间,我只写一个add方法,就是简单的2个数字相加,对于真正的开发中我们肯定会遇到其他类型,java到c/cpp中类型需要转换,具体类型转换对应关系g一下就能得到,我也不在列举。c/cpp中一个class一般包含2个文件,一个头文件定义(h),一个文件主体(c/cpp)。啰嗦了这么多还是直接动手吧,先在vs2008中建立一个工程(当然你也可以直接编写不用这些IDE工具,gcc g++的命令自己g。下同,不在注释不在废话),选取win32工程

键入工程名字testDll,点击next选取DLL,然后点击完成

打开我们的testdllcpp,添加进我们的add方法

C++代码

1int add(int a,int b){

2 return a+b;

3}

int add(int a,int b){

return a+b;

}

注意到文件列表里并没有testDllh,因为我们要给出调用者一个接口,如果不给头文件,人家就没办法调用,所以我们就必须添加一个头文件testDllh。

C++代码

1#ifdef TEST_DLL

2#define TEST_API __declspec(dllexport)

3#else

4#define TEST_API __declspec(dllimport)

5#endif

6

7/ Set up for C function definitions, even when using C++ /

8#ifdef __cplusplus

9extern "C" {

10#endif

11

12TEST_API int add(int,int);

13

14/ Ends C function definitions when using C++ /

15#ifdef __cplusplus

16}

17#endif

#ifdef TEST_DLL

#define TEST_API __declspec(dllexport)

#else

#define TEST_API __declspec(dllimport)

#endif

/ Set up for C function definitions, even when using C++ /

#ifdef __cplusplus

extern "C" {

#endif

TEST_API int add(int,int);

/ Ends C function definitions when using C++ /

#ifdef __cplusplus

}

#endif

在这个头文件中我们把我们的add方法给定义了进去。注意到testdllcpp中#include "stdafxh",所以我们就把这个testDllh include进stdafxh里面。

按道理说我们的这个dll已经完成了,但是一般c/cpp给接口SDK的时候大都给h和lib,为了一步生成dll和lib,我们添加进一个testDlldef,有了这个文件就可以一步生成dll和lib。在source file里右键add new item ,选择Module-Definition File

键入testDll,OK了,我们可以直接build了。生成testDlldll和testDlllib。

把testDlldll扔到system32目录里等待我们高大威猛的java jni调用。

二 JNI

21 编写java文件

为了显示我们的与众相同,我们就把我们的这个java文件命名为Demojava顺便直接带上包名

,因为我们知道人家给我们的接口里有个add方法,所以我们就直接来个调用吧。

Java代码

1package comtestJnitestDemo;

2

3public class Demo {

4 static

5 {

6 //Systemoutprintln(SystemgetProperty("javalibrarypath"));

7 SystemloadLibrary("testDll");

8 SystemloadLibrary("jniDll");

9 }

10 public native static int add(int a,int b);

11

12}

package comtestJnitestDemo;

public class Demo {

static

{

//Systemoutprintln(SystemgetProperty("javalibrarypath"));

SystemloadLibrary("testDll");

SystemloadLibrary("jniDll");

}

public native static int add(int a,int b);

}

demojava代码暂时如此,我们把将要生成的jni的dll叫做jniDll,有童鞋讲,我不想用你这个烂名字jniDll多俗啊,没关系,你可以换,随你换,生成文件后你再换也可以,现在换也可以。

22 生成h头文件

javah命令,不多讲。生成的文件com_testJni_testDemo_Demoh这个文件的命名规则我就不多讲了,一目了然。

C++代码

1/ DO NOT EDIT THIS FILE - it is machine generated /

2#include <jnih>

3/ Header for class com_testJni_testDemo_Demo /

4

5#ifndef _Included_com_testJni_testDemo_Demo

6#define _Included_com_testJni_testDemo_Demo

7#ifdef __cplusplus

8extern "C" {

9#endif

10/

11 Class: com_testJni_testDemo_Demo

12 Method: add

13 Signature: (II)I

14 /

15JNIEXPORT jint JNICALL Java_com_testJni_testDemo_Demo_add

16 (JNIEnv , jclass, jint, jint);

17

18#ifdef __cplusplus

19}

20#endif

21#endif

/ DO NOT EDIT THIS FILE - it is machine generated /

#include <jnih>

/ Header for class com_testJni_testDemo_Demo /

#ifndef _Included_com_testJni_testDemo_Demo

#define _Included_com_testJni_testDemo_Demo

#ifdef __cplusplus

extern "C" {

#endif

/

Class: com_testJni_testDemo_Demo

Method: add

Signature: (II)I

/

JNIEXPORT jint JNICALL Java_com_testJni_testDemo_Demo_add

(JNIEnv , jclass, jint, jint);

#ifdef __cplusplus

}

#endif

#endif

23 用c/cpp实现这个头文件

c/cpp中已经实现了这个add方法,我们只需要调用就可以啦。所以直接vs2008中建立一个dll工程,工程名我们就叫jniDll,具体过程不再多讲,方法同上面testDll的建立一样。在这个工程里kimmking把需要引用的包、文件等已经讲的很清楚了。打开jniDllcpp,添加下面代码

C++代码

1JNIEXPORT jint JNICALL Java_com_testJni_testDemo_Demo_add

2(JNIEnv env,jclass jobject,jint a,jint b){

3

4 return add(a,b);

5}

JNIEXPORT jint JNICALL Java_com_testJni_testDemo_Demo_add

(JNIEnv env,jclass jobject,jint a,jint b){

return add(a,b);

}因为int对应的类型就刚好是jint,所以就不需要转换,其他需要转换的类型自己g对应关系转换,注意释放。

这个工程里我们还需要打开 stdafxh添加

C++代码

1#include <jnih>

2

3#include "testDllh"

4#include "com_testJni_testDemo_Demoh"

#include <jnih>

#include "testDllh"

#include "com_testJni_testDemo_Demoh"

在编译这个jniDll工程的时候需要引入testDllh,com_testJni_testDemo_Demoh,另外添加testDlllib这个依赖。

好了做好这些后,build下,生成了我们期待已久的jniDlldll,把这个dll同样扔到system32下。

三 测试

本人特懒,不想写多余的class,所以直接修改Demojava 这也是刚才为什么讲暂时如此的原因

Java代码

1package comtestJnitestDemo;

2

3public class Demo {

4 static

5 {

6 //Systemoutprintln(SystemgetProperty("javalibrarypath"));

7 SystemloadLibrary("testDll");

8 SystemloadLibrary("jniDll");

9 }

10 public native static int add(int a,int b);

11 public static void main(String[] args) {

12 Systemoutprintln(add(7,2));

13 }

14}

package comtestJnitestDemo;

public class Demo {

static

{

//Systemoutprintln(SystemgetProperty("javalibrarypath"));

SystemloadLibrary("testDll");

SystemloadLibrary("jniDll");

}

public native static int add(int a,int b);

public static void main(String[] args) {

Systemoutprintln(add(7,2));

}

}

四 最后补充

如果系统已经加载过c/cpp的dll,我们就不用再SystemloadLibrary("testDll")了,加载一遍就可以了,因为我们刚才写的testDll系统没有加载,所以我就加载了一下。对于多个dll可以写多个SystemloadLibrary去加载,修改static{}里面的内容不需要重新生成dll,除非你多加了一个调用方法,如果你看清楚规则,就不用javah命令就可以直接编写头文件,用javah太麻烦了。

在JDK8之前,静态成员(静态变量和静态方法)都是存储在方法区(永久代)中的静态区中(这里指类被加载后,静态成员的存储位置)。但在JDK8之后,永久代被移除了,取而代之的是元空间(metaspace)。但元空间中存储的主要是class文件的元数据信息,静态成员的存储位置由方法区转到了堆内存(heap)中。

不过,不管是JDK8,还是更早的版本中,静态方法的执行(不仅仅是静态方法,还有普通的成员方法)都是在栈内存(stack)中进行的。每个线程都会在栈内存中开辟一个栈,在调用方法时,对应的方法都会在执行这个方法的线程的栈中创建一个“栈帧”,栈帧中保存了局部变量表(基本数据类型和对象引用)、 *** 作数栈、动态连接和返回地址等信息。等到方法执行完毕,栈帧被销毁,对应的内存也将被释放。

 Oracle自带一个JVM 内置对Java的支持 任何Java能做的事情你都可以放到Oracle里面来做 你甚至可以在里面 *** 作db 这让Oracle具备了极其巨大的扩展能力 只要你愿意 完全可以开发一个trigger 让它在适当的时候给管理员的msn发送一条即时消息

 由于ps/SQL是过程化的语言 它基本上不具备多态的概念 供Oracle使用的Java方法必须申明为static 所以在Oracle中你无法使用Java的动态特性 比如接口 反射等 不过这并不妨碍你用Java 做的事

 我们以一个简单的hello world为例 我想任何一个有经验的Java程序员都能够通过这个例子 派生出其他希奇古怪的应用 有好的创意记得要与我共享 我的msn是

 首先是创建一个Java类 启动SQL plus 执行如下命令

 create or replace and pile java source named hello_sp as

 package bromon oracle;

 public class Hello

 {

 public static String say(String name)

 {

 return 你好 +name;

 }

 }

 Java程序已创建

 然后在Oracle中把这个类导入成为一个函数 执行命令

 create or replace function hello_sp(name varchar ) return varchar

 as language java name

  bromon oracle Hello say(java lang String) return java lang String ;

 函数已创建

 现在可以调用该函数 执行

 select hello( bromon ) from dual;

 返回结果 你好 bromon

 有一个需要注意的问题是 假如我们的java方法是没有参数的 比如

 public static String say()

 {

 return 你好 ;

 }

 那么在创建函数的时候 函数名不应该有扩号 hello_sp 否则会报告函数有编译错误

 如果你的Java类是在IDE里面编写的 那么只需要在oracle中加载编译过的class文件即可 方法是

lishixinzhi/Article/program/Oracle/201311/18111

一、函数的定义及特点

1) 什么是函数?

函数就是定义在类中的具有特定功能的一段独立小程序,函数也称为方法

2)Java中函数的格式:

修饰符 返回值类型函数名(参数类型 形式参数1,参数类型 形式参数2,。。)

{ 执行语句;

return 返回值;

返回值类型:函数运行后的结果的数据类型

参数类型:是形式参数的数据类型

形式参数:是一个变量,用于存储调用函数时传递给函数的实际参数

实际参数:传递给形式参数的具体数值

return:用于结束函数

返回值:该值会返回给调用者

3) 函数的特点

a) 定义函数可以将功能代码进行封装

b) 便于对该功能进行复用

c) 函数只有被调用才会被执行

d) 函数的出现提高了代码的复用性

e) 对于函数没有具体返回值的情况,返回值类型用关键字void表示,那么该函数中的return语句如果在最后一行可以省略不写,系统会帮你自动加上。

注:

a) 函数中只能调用函数,不可以在函数内部定义函数。

b) 定义函数时,函数的结果应该返回给调用者,交由调用者处理。

c) 当函数运算后,没有具体的返回值时,这是返回值类型用一个特殊的关键字来标识该关键字就是void,void:代表的是函数没有具体返回值的情况。

d) 当函数的返回值类型是void时,函数中的return语句可以省略不写。

4) 如何定义一个函数?

函数其实就是一个功能,定义函数就是实现功能,通过两个明确来完成:

1)、明确该功能的运算完的结果,其实是在明确这个函数的返回值类型。

2)、在实现该功能的过程中是否有未知内容参与了运算,其实就是在明确这个函数的参数列表(参数类型&参数个数)。

5) 函数的作用:

1)、用于定义功能。

2)、用于封装代码提高代码的复用性。

注意:函数中只能调用函数,不能定义函数。

6) 主函数:

1)、保证该类的独立运行。

2)、因为它是程序的入口。

3)、因为它在被jvm调用。

7) 函数定义名称是为什么呢?

答:1)、为了对该功能进行标示,方便于调用。

2)、为了通过名称就可以明确函数的功能,为了增加代码的阅读性。

二、函数的应用

1) 两个明确

a) 明确要定义的功能最后的结果是什么?

b) 明确在定义该功能的过程中,是否需要未知内容参与运算

2) 示例:

举例1:

复制代码代码如下:

class FunctionDemo

{

public static void main(String[] args)

{

int x = 4;

Systemoutprintln(x3+5);

x = 6;

Systemoutprintln(x3+5);

int y = 43+5;

int z = 63+5;

Systemoutprintln(y);

Systemoutprintln(z);

}

}

发现以上的运算,因为获取不同数据的运算结果,代码出现了重复。

为了提高代码的复用性。对代码进行抽取。将这个部分定义成一个独立的功能。方便与日后使用。

java中对功能的定义是通过函数的形式来体现的。

明确功能:需要定义功能,完成一个整数的3+5的运算,

1,先明确函数定义的格式。

/

修饰符返回值类型函数名(参数类型形式参数1,参数类型形式参数2,)

{

执行语句;

return 返回值;

}

复制代码代码如下:

class FunctionDemo

{

public static void getResult(int num)

{

Systemoutprintln(num 3 + 5);

return;//可以省略

}

public static void main(String[] args)

{

getResult(5);

}

}

对上述关于return是否省略这一小小知识点的总结:

当函数运算后,没有具体的返回值时,这是返回值类型用一个特殊的关键字来标识。

该关键字就是void。void:代表的是函数没有具体返回值的情况。

当函数的返回值类型是void时,函数中的return语句可以省略不写。

举例2:

复制代码代码如下:

class FunctionDemo2

{

public static void main(String[] args)

{

int sum = getSum(4,6);

Systemoutprintln("sum="+sum);

sum = getSum(2,7);

Systemoutprintln("sum="+sum);

}

/下面的这个功能定义思想有问题,为什么呢?因为只为完成加法运算,至于是否要对和进行打印 *** 作,

那是调用者的事,不要在该功能中完成。/

public static void get(int a,int b)

{

Systemoutprintln(a+b);

return ;

}

}

如何定义一个函数呢?

1,既然函数是一个独立的功能,那么该功能的运算结果是什么先明确

因为这是在明确函数的返回值类型。

2,在明确在定义该功能的过程中是否需要未知的内容参与运算。

因为是在明确函数的参数列表(参数的类型和参数的个数)。

复制代码代码如下:

class FunctionDemo2

{

public static void main(String[] args)

{

/

int sum = getSum(4,6);

Systemoutprintln("sum="+sum);

sum = getSum(2,7);

Systemoutprintln("sum="+sum);

/

//get(4,5);

int x = getSum(4,4);

int y = getSum(7,9);

int num = getMax(x,y);

}

//需求:定义一个功能。完成3+4的运算。并将结果返回给调用者。

/

1,明确功能的结果:是一个整数的和。

2,在实现该功能的过程中是否有未知内容参与运算,没有。

其实这两个功能就是在明确函数的定义。

1,是在明确函数的返回值类型。

2,明确函数的参数列表( 参数的类型和参数的个数)。

/

public static int getSum()

{

return 3+4;

}

/

以上这个函数的功能,结果是固定的,毫无扩展性而言。

为了方便用户需求。由用户来指定加数和被加数。这样,功能才有意义。

思路:

1,功能结果是一个和。返回值类型是int。

2,有未知内容参与运算。有两个。这个两个未知内容的类型都是int。

/

public static int getSum(int x,int y)

{

return x+y;

}

/

需求:判断两个数是否相同。

思路:

1,明确功能的结果:结果是:boolean 。

2,功能是否有未知内容参与运算。有,两个整数。

/

public static boolean compare(int a,int b)

{

/

if(a==b)

return true;

//else

return false;

/

//return (a==b)true:false;

return a==b;

}

/

需求:定义功能,对两个数进行比较。获取较大的数。

/

public static int getMax(int a,int b)

{

/

if(a>b)

return a;

else

return b;

//或者用下面的三元运算符

/

return (a>b)a:b;

}

}

3) 练习:

1,定义一个功能,用于打印矩形。

2,定义一个打印99乘法表功能的函数。

复制代码代码如下:

class FunctionTest

{

public static void main(String[] args)

{

draw(5,6);

printHr();

draw(7,9);

printHr();

print99();

}

/

定义一个功能,用于打印矩形。

思路:

1,确定结果:没有,因为直接打印。所以返回值类型是void

2,有未知内容吗?有,两个,因为矩形的行和列不确定。

/

public static void draw(int row,int col)

{

for(int x=0; x<row; x++)

{

for(int y=0; y<col; y++)

{

Systemoutprint("");

}

Systemoutprintln();

}

}

public static void printHr()

{

Systemoutprintln("------------------------------");

}

/

定义一个打印99乘法表功能的函数。

/

public static void print99()

{

for(int x=1; x<=9; x++)

{

for(int y=1; y<=x; y++)

{

Systemoutprint(y+""+x+"="+yx+"\t");

}

Systemoutprintln();

}

}

}

三、函数的重载(overload)

重载的概念:

在同一个类中,允许存在一个以上的同名函数,只要它们的参数个数或者参数类型不同即可。

重载的特点:

与返回值类型无关,只看参数列表。

重载的好处:

方便于阅读,优化了程序设计。

重载示例:

返回两个整数的和

int add(int x,int y){return x+y;}

返回三个整数的和

int add(int x,int y, int z){return x+y+z;}

返回两个小数的和

double add(double x,double y){return x+y;}

什么时候用重载?

当定义的功能相同,但参与运算的未知内容不同。

那么,这时就定义一个函数名称以表示起功能,方便阅读,而通过参数列表的不同来区分多个同名函数。

重载范例:

复制代码代码如下:

class FunctionOverload

{

public static void main(String[] args)

{

add(4,5);

add(4,5,6);

print99();

}

public static void print99(int num)

{

for(int x=1; x<=num; x++)

{

for(int y=1; y<=x; y++)

{

Systemoutprint(y+""+x+"="+yx+"\t");

}

Systemoutprintln();

}

}

//打印99乘法表

public static void print99()

{

print99(9);

}

//定义一个加法运算,获取两个整数的和。

public static int add(int x,int y)

{

return x+y;

}

//定义一个加法,获取三个整数的和。

public static int add(int x,int y,int z)

{

return add(x,y)+z;

}

}

练习:区分是否是重载

复制代码代码如下:

void show(int a,char b,double c){}

下面的a,b,c,d,e,f与上述一句的区别:

a

void show(int x,char y,double z){}//没有,因为和原函数一样。

b

int show(int a,double c,char b){}//重载,因为参数类型不同。注意:重载和返回值类型没关系。

c

void show(int a,double c,char b){}//重载,因为参数类型不同。注意:重载和返回值类型没关系。

d

boolean show(int c,char b){}//重载了,因为参数个数不同。

e

void show(double c){}//重载了,因为参数个数不同。

f

double show(int x,char y,double z){}//没有,这个函数不可以和给定函数同时存在与一个类中。

如何区分重载:当函数同名时,只看参数列表。和返回值类型没关系。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/12176324.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-21
下一篇2023-05-21

发表评论

登录后才能评论

评论列表(0条)

    保存