用java的jni调用C语言的API,实现带图形界面的一元稀疏多项式计算器

来源:互联网 发布:爱家呐软件多少钱 编辑:程序博客网 时间:2024/06/06 10:02

实现步骤:

1) 完成Java代码,编写好Java调用类。

2) 编译你的Java类。

3) 用javah生成编译好的class文件对应的C/C++ 函数的头文件。

4) 实现头文件中的函数原型,编写native代码。

5) 将native代码编译打包成DLL库(win32)或共享库(Linux)。

6) 将你的Java代码跑起来


一、首先在创建一个类InvokerHelper。

1. 编写Java代码。

注意:

(1) 调用本地代码的java方法,要设置成native的。

(2) 要使用System的LoadLibrary方法去加载包含本地方法实现的库。

/src/helper/InvokerHelper.java

package helper;public class InvokerHelper {static {System.loadLibrary("PolynomialCaculator");}// 多项式相加public static native String AddPolyn(int n1, float[] coef1, int[] expn1, int n2, float[] coef2, int[] expn2);// 多项式相加public static native String SubtractPolyn(int n1, float[] coef1, int[] expn1, int n2, float[] coef2, int[] expn2);// 多项式相加public static native String MultiplyPolyn(int n1, float[] coef1, int[] expn1, int n2, float[] coef2, int[] expn2);}
2、编译生成InvokerHelper.class

3、在cmd命令行中切换至eclipse的对应的workspace的bin目录下,执行命令javah -classpath . -jni helper.InvokerHelper。此处的helper为包         名,InvokerHelper为类名。此时生成一个helper_InvokerHelper.h文件。内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class helper_InvokerHelper */#ifndef _Included_helper_InvokerHelper#define _Included_helper_InvokerHelper#ifdef __cplusplusextern "C" {#endif/* * Class:     helper_InvokerHelper * Method:    AddPolyn * Signature: (I[F[II[F[I)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_helper_InvokerHelper_AddPolyn  (JNIEnv *, jclass, jint, jfloatArray, jintArray, jint, jfloatArray, jintArray);/* * Class:     helper_InvokerHelper * Method:    SubtractPolyn * Signature: (I[F[II[F[I)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_helper_InvokerHelper_SubtractPolyn  (JNIEnv *, jclass, jint, jfloatArray, jintArray, jint, jfloatArray, jintArray);/* * Class:     helper_InvokerHelper * Method:    MultiplyPolyn * Signature: (I[F[II[F[I)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_helper_InvokerHelper_MultiplyPolyn  (JNIEnv *, jclass, jint, jfloatArray, jintArray, jint, jfloatArray, jintArray);#ifdef __cplusplus}#endif#endif

4) 实现头文件中的函数原型,编写native代码。

创建一个DLL项目,这里我用devc++创建。文件->新建->项目->选择DLL工程。

以下有几个特别值得注意的地方:

1、要将生成的helper_InvokerHelper.h文件放到DLL工程的根目录,并将文件开头的#include <jni.h>改成#include "jni.h"

2、找到jdk的安装目录的jni.h与jni_md.h文件,将这两个文件复制到DLL工程的根目录。默认安装的话,这两个文件的路径为C:\Program Files\Java\jdk1.8.0_40\include和C:\Program Files\Java\jdk1.8.0_40\include\win32


接下来实现创建新的.c或.cpp文件(分别为C文件和C++文件),实现helper_InvokerHelper.h头文件中的方法,文件名应该与之前java的helper_InvokerHelper类中的System.loadLibrary()的名称相同。此处为我用C++语言,所以为PolynomialCaculator.cpp。将helper_InvokerHelper.h头文件中的方法复制粘贴到PolynomialCaculator.cpp,将方法逐一实现。

代码如下:

#include<stdio.h>#include "helper_InvokerHelper.h"#include "jni.h"#include<math.h>#include<stdlib.h>  #include<string.h>typedef struct Polynomial{    float               coef;     //系数    int                 expn;     //指数    struct Polynomial  *next;}*Polyn,Polynomial;void Insert(Polyn p,Polyn h){         if(p->coef==0) free(p);       //系数为0的话释放结点    else{        Polyn q1,q2;        q1=h;q2=h->next;        while(q2&& p->expn < q2->expn){                        //查找插入位置            q1=q2;            q2=q2->next;}        if(q2&& p->expn == q2->expn){                        //将指数相同相合并            q2->coef += p->coef;            free(p);            if(!q2->coef){                    //系数为0的话释放结点                q1->next=q2->next;                free(q2);}}        else{                       //指数为新时将结点插入            p->next=q2;            q1->next=p;}}}Polyn CreatePolyn(int n, float coef[], int expn[]){                 //建立一个头指针为head、项数为m的一元多项式    int     i;    Polyn   p,head;    p=head=(Polyn)malloc(sizeof(struct Polynomial));    head->next=NULL;    for(i=0;i<n;i++){        p=(Polyn)malloc(sizeof(struct Polynomial));  //建立新结点以接收数据        p->coef=coef[i];        p->expn=expn[i];        Insert(p,head);                              //调用Insert函数插入结点}    return head;}int compare(Polyn a,Polyn b){//比较多项式的指数的大小     if(a&&b){        if(!b||a->expn>b->expn) return 1;        else if(!a||a->expn<b->expn) return -1;        else return 0;}    else if(!a&&b) return -1;                    //a多项式已空,但b多项式非空    else return 1;                               //b多项式已空,但a多项式非空}jstring PrintPolyn(Polyn P,JNIEnv * env){char buf[50];int a;int i=0;//指向下一个插入地址 int k=0;Polyn q=P->next;     int flag=1;                  //项数计数器    if(!q){                            //若多项式为空,输出0         buf[i]=0;        i++;        buf[i]=230;         i++;         char* tmpstr=buf;         jstring rtstr = env->NewStringUTF(tmpstr);          return rtstr;}          while(q){//分离整数部分与小数部分int xiaoshu=((int)fabs(q->coef*10))%10; //第一位小数           if(q->coef>0&& flag!=1){  buf[i]='+'; //系数大于0且不是第一项  i++;  printf("+");}           if(q->coef!=1&&q->coef!=-1){                           //系数非1或-1的普通情况     if(q->coef<0)              {   //添加负号     buf[i]='-';    i++;    printf("-");}//添加整数部分        buf[i]=(int)(fabs(q->coef));        i++;         printf("%d",(int)(fabs(q->coef)));        if(xiaoshu!=0)    {    //添加小数点buf[i]='.';    i++;    printf(".");    //添加小数部分      buf[i]=xiaoshu;                 i++;                 printf("%d",xiaoshu);}                        if(q->expn==1){  buf[i]='X';                  i++;                  printf("X"); }             else if(q->expn){buf[i]='X';i++;printf("X");buf[i]='^';i++;printf("^");//添加指数的各位数      buf[i]=q->expn;        i++;         printf("%d",q->expn); } }        else{            if(q->coef==1){                if(!q->expn){buf[i]=1;i++;printf("1"); }                 else if(q->expn==1){buf[i]='X';i++;printf("X");}                else{buf[i]='X';i++;printf("X");buf[i]='^';i++;printf("^");//添加指数的各位数     buf[i]=q->expn;        i++;         printf("%d",q->expn); }}           else if(q->coef==-1){                if(!q->expn){buf[i]='-';i++;printf("-");buf[i]=1;i++;printf("1"); }                 else if(q->expn==1){buf[i]='-';i++;printf("-");buf[i]='X';i++;printf("X"); }                 else{buf[i]='-';i++;printf("-");buf[i]='X';i++;printf("X");buf[i]='^';i++;printf("^");//添加指数的各位数     buf[i]=q->expn;            i++;             printf("%d",q->expn); } }}        q=q->next;         flag++;}buf[i]='\0';    char shu[strlen(buf)];    strcpy(shu,buf);char* tmpstr=shu;     jstring rtstr = env->NewStringUTF(tmpstr);      return rtstr;}Polyn AddPolyn(Polyn pa,Polyn pb){               //求解并建立多项式a+b,返回其头指针    Polyn qa=pa->next;    Polyn qb=pb->next;    Polyn headc,hc,qc;    hc=(Polyn)malloc(sizeof(struct Polynomial)); //建立头结点    hc->next=NULL;    headc=hc;    while(qa||qb){        qc=(Polyn)malloc(sizeof(struct Polynomial));        switch(compare(qa,qb)){        case 1:{                qc->coef=qa->coef;                qc->expn=qa->expn;                qa=qa->next;                break;}        case 0:{                 qc->coef=qa->coef+qb->coef;                qc->expn=qa->expn;                qa=qa->next;                qb=qb->next;                break;}        case -1:{                qc->coef=qb->coef;                qc->expn=qb->expn;                qb=qb->next;                break;} }        if(qc->coef!=0){            qc->next=hc->next;            hc->next=qc;            hc=qc;}    else free(qc);                               //当相加系数为0时,释放该结点}    return headc;}JNIEXPORT jstring JNICALL Java_helper_InvokerHelper_AddPolyn  (JNIEnv * env, jclass method, jint n1, jfloatArray coef1, jintArray expn1, jint n2, jfloatArray coef2, jintArray expn2){    jfloat* c1 = (env)->GetFloatArrayElements(coef1,0);  jint* e1 = (env)->GetIntArrayElements(expn1, 0 );  float c11[n1];  int e11[n1];  int i;  for(i=0;i<n1;i++)  {  c11[i]=c1[i];  e11[i]=e1[i];  }  (env)->ReleaseFloatArrayElements(coef1, c1, 0 );  (env)->ReleaseIntArrayElements(expn1, e1, 0 );    jfloat* c2 = (env)->GetFloatArrayElements(coef2, 0 );  jint* e2 = (env)->GetIntArrayElements(expn2, 0 );  float c22[n2];  int e22[n2];  for(i=0;i<n2;i++)  {  c22[i]=c2[i];  e22[i]=e2[i];  }  env->ReleaseFloatArrayElements(coef2, c2, 0 );  env->ReleaseIntArrayElements(expn2, e2, 0 );      Polyn pa=CreatePolyn(n1,c11,e11);  Polyn pb=CreatePolyn(n2,c22,e22);    Polyn qa=pa->next;    Polyn qb=pb->next;    Polyn headc,hc,qc;    hc=(Polyn)malloc(sizeof(struct Polynomial)); //建立头结点    hc->next=NULL;    headc=hc;    while(qa||qb){         qc=(Polyn)malloc(sizeof(struct Polynomial));        switch(compare(qa,qb)){        case 1:{                qc->coef=qa->coef;                qc->expn=qa->expn;                qa=qa->next;                break;}        case 0:{                 qc->coef=qa->coef+qb->coef;                qc->expn=qa->expn;                qa=qa->next;                qb=qb->next;                break;}        case -1:{                qc->coef=qb->coef;                qc->expn=qb->expn;                qb=qb->next;                break;} }        if(qc->coef!=0){            qc->next=hc->next;            hc->next=qc;            hc=qc;}    else free(qc);                               //当相加系数为0时,释放该结点}//测试代码   return PrintPolyn(headc,env);  }    JNIEXPORT jstring JNICALL Java_helper_InvokerHelper_SubtractPolyn  (JNIEnv * env, jclass method, jint n1, jfloatArray coef1, jintArray expn1, jint n2, jfloatArray coef2, jintArray expn2)  {    jfloat* c1 = (env)->GetFloatArrayElements(coef1,0);  jint* e1 = (env)->GetIntArrayElements(expn1, 0 );  float c11[n1];  int e11[n1];  int i;  for(i=0;i<n1;i++)  {  c11[i]=c1[i];  e11[i]=e1[i];  }  (env)->ReleaseFloatArrayElements(coef1, c1, 0 );  (env)->ReleaseIntArrayElements(expn1, e1, 0 );    jfloat* c2 = (env)->GetFloatArrayElements(coef2, 0 );  jint* e2 = (env)->GetIntArrayElements(expn2, 0 );  float c22[n2];  int e22[n2];  for(i=0;i<n2;i++)  {  c22[i]=c2[i];  e22[i]=e2[i];  }  env->ReleaseFloatArrayElements(coef2, c2, 0 );  env->ReleaseIntArrayElements(expn2, e2, 0 );      Polyn pa=CreatePolyn(n1,c11,e11);  Polyn pb=CreatePolyn(n2,c22,e22);    Polyn h=pb;    Polyn p=pb->next;    Polyn pd;    while(p){                                           //将pb的系数取反        p->coef*=-1;        p=p->next;}    pd=AddPolyn(pa,h);    for(p=h->next;p;p=p->next)                   //恢复pb的系数        p->coef*=-1;    return PrintPolyn(pd,env);  }      JNIEXPORT jstring JNICALL Java_helper_InvokerHelper_MultiplyPolyn  (JNIEnv * env, jclass method, jint n1, jfloatArray coef1, jintArray expn1, jint n2, jfloatArray coef2, jintArray expn2)  {    jfloat* c1 = (env)->GetFloatArrayElements(coef1,0);  jint* e1 = (env)->GetIntArrayElements(expn1, 0 );  float c11[n1];  int e11[n1];  int i;  for(i=0;i<n1;i++)  {  c11[i]=c1[i];  e11[i]=e1[i];  }  (env)->ReleaseFloatArrayElements(coef1, c1, 0 );  (env)->ReleaseIntArrayElements(expn1, e1, 0 );    jfloat* c2 = (env)->GetFloatArrayElements(coef2, 0 );  jint* e2 = (env)->GetIntArrayElements(expn2, 0 );  float c22[n2];  int e22[n2];  for(i=0;i<n2;i++)  {  c22[i]=c2[i];  e22[i]=e2[i];  }  env->ReleaseFloatArrayElements(coef2, c2, 0 );  env->ReleaseIntArrayElements(expn2, e2, 0 );      Polyn pa=CreatePolyn(n1,c11,e11);  Polyn pb=CreatePolyn(n2,c22,e22);     Polyn hf,pf;    Polyn qa=pa->next;    Polyn qb=pb->next;    hf=(Polyn)malloc(sizeof(struct Polynomial));//建立头结点    hf->next=NULL;    for(;qa;qa=qa->next){        for(qb=pb->next;qb;qb=qb->next){            pf=(Polyn)malloc(sizeof(struct Polynomial));            pf->coef=qa->coef*qb->coef;            pf->expn=qa->expn+qb->expn;            Insert(pf,hf);                    //调用Insert函数以合并指数相同的项}}return PrintPolyn(hf,env);  }


5) 将native代码编译打包成DLL库(win32)或共享库(Linux)。

编译PolynomialCaculator.cpp,将会获得PolynomialCaculator.dll文件,将该文件复制粘贴到java工程的根目录,这个目录非常重要,不要弄错。为了防止大家出错,贴出我的工程目录截图



6) 将你的Java代码跑起来

    即调用InvokerHelper类里定义的方法,只要像调用普通的额Java类的方法一样就可以了

   这里将我写的一元稀疏多项式的界面代码是功能实现也贴出来:

/src/view/CalculatorUI.java

package view;import java.awt.Dimension;import java.awt.FlowLayout;import java.awt.Font;import java.awt.GridLayout;import java.awt.Toolkit;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.util.regex.Matcher;import java.util.regex.Pattern;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JOptionPane;import javax.swing.JPanel;import javax.swing.JTextArea;import helper.InvokerHelper;public class CalculatorUI extends JFrame implements ActionListener {private JTextArea answerText;private JPanel panel;private String[] btString = { "^", "(", ")", "计算", "7", "8", "9", "-", "4", "5", "6", "+", "1", "2", "3", "0", "C","x", "*" };// 存储两个多项式的系数与指数private float[] coef1;private int[] expn1;private float[] coef2;private int[] expn2;private String operator;public CalculatorUI() {// (6x-3-x+4.4x2-1.2x9) (-6x-3+5.4x2-x2+7.8x15) sssssssssssanswerText = new JTextArea(1, 37);GridLayout layout = new GridLayout(5, 4, 4, 4);panel = new JPanel(layout);panel.setPreferredSize(new Dimension(450, 200));this.setLayout(new FlowLayout());this.setTitle("一元稀疏多项式计算器");answerText.setFont(new Font("TimesRoman", Font.BOLD, 15));for (int i = 0; i < btString.length; i++) {JButton bt = new JButton(btString[i]);bt.addActionListener(this);panel.add(bt);}this.add(answerText);this.add(panel);Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();int width = screenSize.width;int height = screenSize.height;this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setSize(450, 270);this.setResizable(false);this.setLocation(width / 2 - 215, height / 2 - 165);this.setVisible(true);}@Overridepublic void actionPerformed(ActionEvent event) {String c = event.getActionCommand();switch (c) {case "计算":analyseFormular(answerText.getText());break;case "C":answerText.setText("");break;default:answerText.append(c);}}private void analyseFormular(String s) {// (2x^2+3x^3)+(3x^3+4x^4)if (!verifyFormula(s)) {JOptionPane.showMessageDialog(this, "式子不匹配,式子应符合(多项式1)+或-或*(多项式2)");return;}getOperator(s);getArrayData(s);Calculate();}private void Calculate() {String answer;switch (operator) {case "+":// getAnswer(answer)System.out.println("加法");answer = InvokerHelper.AddPolyn(coef1.length, coef1, expn1, coef2.length, coef2, expn2);answerText.setText(getAnswer(answer));break;case "-":System.out.println("减法");answer = InvokerHelper.SubtractPolyn(coef1.length, coef1, expn1, coef2.length, coef2, expn2);answerText.setText(getAnswer(answer));break;case "*":System.out.println("乘法");answer = InvokerHelper.MultiplyPolyn(coef1.length, coef1, expn1, coef2.length, coef2, expn2);answerText.setText(getAnswer(answer));break;}}private String getAnswer(String answer) {StringBuilder result = new StringBuilder("");int i = 0;if (answer.length() > 0)for (i = 0; i < answer.length() && ((int) answer.charAt(i)) != 254; i++) {if (answer.charAt(i) == 'X' || answer.charAt(i) == '^' || answer.charAt(i) == '+'|| answer.charAt(i) == '-' || answer.charAt(i) == '.') {result.append(answer.charAt(i));System.out.print("," + answer.charAt(i));} else {result.append((int) answer.charAt(i));System.out.print("," + (int) answer.charAt(i));}}elseresult.append("0");return result.toString();}private void getOperator(String s) {if (s.contains(")+("))operator = "+";else if (s.contains(")-("))operator = "-";else if (s.contains(")*("))operator = "*";}private void getArrayData(String s) {// 获得两个多项式String forArr[] = s.split("\\)([+-]|\\*)\\(");String xiang = "((-?[0-9]+\\.?[0-9]*)|-)?x(\\^-?[0-9]+)?\\b|-?[0-9]+\\.?[0-9]*\\b";// 多项式每一项的正则表达式Pattern pattern = Pattern.compile(xiang);Matcher matcher;String[] arr1;String[] arr2;int num1 = 0;int num2 = 0;matcher = pattern.matcher(forArr[0]);while (matcher.find()) {num1++;}matcher = pattern.matcher(forArr[1]);while (matcher.find()) {num2++;}coef1 = new float[num1];expn1 = new int[num1];coef2 = new float[num2];expn2 = new int[num2];arr1 = new String[num1];arr2 = new String[num2];matcher = pattern.matcher(forArr[0]);int i = 0;while (matcher.find()) {arr1[i] = matcher.group();i++;}i = 0;matcher = pattern.matcher(forArr[1]);while (matcher.find()) {arr2[i] = matcher.group();i++;}String[] str;for (i = 0; i < arr1.length; i++) {System.out.println(arr1[i]);if (arr1[i].equals("x")) {coef1[i] = 1;expn1[i] = 1;} else if (arr1[i].equals("-x")) {coef1[i] = -1;expn1[i] = 1;} else if (!arr1[i].contains("x")) {// 整数coef1[i] = Float.parseFloat(arr1[i]);expn1[i] = 0;} else if (arr1[i].endsWith("x") && !arr1[i].contains("^")) {// 2x,3x这种形式coef1[i] = Float.parseFloat(arr1[i].replace("x", ""));expn1[i] = 1;} else if (arr1[i].startsWith("x") && arr1[i].contains("^")) {// x^3这种形式coef1[i] = 1;expn1[i] = Integer.parseInt(arr1[i].replace("x^", ""));} else {str = arr1[i].split("x\\^");if (str[0].equals("-"))coef1[i] = -1;elsecoef1[i] = Float.parseFloat(str[0]);expn1[i] = Integer.parseInt(str[1]);}System.out.println("系数:指数=" + coef1[i] + "," + expn1[i]);}for (i = 0; i < arr2.length; i++) {System.out.println(arr2[i]);if (arr2[i].equals("x")) {coef2[i] = 1;expn2[i] = 1;} else if (arr2[i].equals("-x")) {coef2[i] = -1;expn2[i] = 1;} else if (!arr2[i].contains("x")) {// 整数coef2[i] = Float.parseFloat(arr2[i]);expn2[i] = 0;} else if (arr2[i].endsWith("x") && !arr2[i].startsWith("x")) {// 2x,3x这种形式coef2[i] = Float.parseFloat(arr2[i].replace("x", ""));expn2[i] = 1;} else if (arr2[i].startsWith("x") && arr2[i].contains("^")) {// x^3这种形式coef2[i] = 1;expn2[i] = Integer.parseInt(arr2[i].replace("x^", ""));} else {str = arr2[i].split("x\\^");if (str[0].equals("-"))coef2[i] = -1;elsecoef2[i] = Float.parseFloat(str[0]);expn2[i] = Integer.parseInt(str[1]);}System.out.println("系数:指数=" + coef2[i] + "," + expn2[i]);}System.out.println("第一个多项式:");for (i = 0; i < coef1.length; i++)System.out.println(coef1[i] + ":" + expn1[i]);System.out.println("第二个多项式:");for (i = 0; i < coef2.length; i++)System.out.println(coef2[i] + ":" + expn2[i]);}// 验证表达式是否正确private boolean verifyFormula(String s) {boolean b = false;String duoxiangshi = "\\((([+-]?[0-9]+\\.?[0-9]*)|(([+-]?[0-9]+\\.?[0-9]*)|-)*x(\\^-?[0-9]+)?)(([+-])(([0-9]+\\.?[0-9]*)|(([0-9]+\\.?[0-9]*)|-)*x(\\^-?[0-9]+)?))*\\)";String regex = duoxiangshi + "([+-]|\\*)" + duoxiangshi;Pattern pattern = Pattern.compile(regex);Matcher matcher = pattern.matcher(s);b = matcher.matches();return b;}}
这时一个有图形界面的一元稀疏多项式就完成了。



我在写这个小项目时候遇到的其他问题还包括

1、用正则表达式解析字符串,关于正则表达式,如果大家没有接触过,推荐给大家一个网址,非常有用

http://deerchao.net/tutorials/regex/regex.htm#howtouse

2、dll中C的返回值类型和java的接收的类型,这个对于刚接触java的jni的新手来说也是一个很头疼的问题。

3、在学习jni的过程中,还了解到可以用java封装好的jna,jna比jni的编程过程更佳简易


感悟:

写这个带图形界面的一元稀疏多项式计算器,完全只是处于感兴趣。本来是一个难度系数最低的课设,但后来脑洞大开想加入界面。但由于没学过用C写界面,而自己又有一定的swing编程基础,之前也听过不同语言混合开发一个程序。于是便开始在网上搜索资料。由此便一发不可收拾了,时时刻刻都在弄这个,因为领悟能力有限,有四五天是熬夜熬到凌晨三四点,最终经过四五天才完成这个作业。写完这个小项目,满满的成就感。希望大家不要被遇到的困难击退,坚持下来,总会有收获的



1 0
原创粉丝点击